• 产品简介
  • 快速开始
    • Agent 开发
    • 导入 Git 仓库
    • 从模板开始
    • 直接上传
    • 从 AI 开始
  • 框架指南
    • Agent
    • 前端
      • Vite
      • React
      • Vue
      • Hugo
      • 其他框架
    • 后端
    • 全栈
      • Next.js
      • Nuxt
      • Astro
      • React Router
      • SvelteKit
      • TanStack Start
      • Vike
    • 自定义 404 页面
  • 项目指南
    • 项目管理
    • edgeone.json
    • 缓存配置
    • 构建输出配置
    • 错误码
  • 构建指南
  • 部署指南
    • 概览
    • 触发部署
    • 管理部署
    • 部署按钮
    • 使用 Github Action
    • 使用 Gitlab CI/CD
    • 使用 CNB 插件
    • 使用 IDE 插件
    • 使用 CodeBuddy IDE
  • 域名管理
    • 概览
    • 自定义域名
    • 配置 HTTPS 证书
      • 概览
      • 申请免费证书
      • 使用 SSL 托管证书
    • 配置 DNS 的 CNAME 记录
  • 企业解决方案
    • Vibe Coding
    • 平台与多租户
    • 内部应用
  • 可观测性
    • 概览
    • 指标分析
    • 日志分析
  • Functions
    • 概览
    • Edge Functions
    • Cloud Functions
      • 概览
      • Node.js
      • Python
      • Go
  • Agents
    • 概览
    • 快速开始
    • 会话管理
    • 可观测
    • 沙箱工具
      • 概览
      • Agent 框架使用
      • 沙箱原子 API
      • 网络搜索工具
    • Agent 鉴权
  • Models
    • 概览
    • 模型与厂商
      • 概览
      • 使用厂商密钥
        • OpenAI
        • Anthropic
        • Google AI Studio
        • DeepSeek
        • MiniMax
        • 混元
        • 智谱
        • 月之暗面
    • 常见问题
  • 存储
    • 概览
    • KV
    • Blob
  • 中间件
  • AI 原生开发
    • Skills
    • MCP
  • Copilot
    • 概览
    • 快速开始
  • API Token
  • EdgeOne CLI
  • 消息通知
  • 集成指南
    • AI
      • 对话型大模型集成
      • 图片大模型集成
    • 数据库
      • Supabase 集成
      • Pages KV 集成
    • 电商
      • Shopify 集成
      • WooCommerce 集成
    • 支付
      • Stripe 集成
      • Paddle 集成
    • CMS
      • WordPress 集成
      • Contentful 集成
      • Sanity 集成
      • Payload 集成
    • 身份验证
      • Supabase 集成
      • Clerk 集成
  • 最佳实践
    • 为网站添加 AI 对话助手
    • AI 对话式部署:使用 Skill 一句话部署项目
    • 使用通用大模型快速搭建 AI 应用
    • 使用 Shopify 搭建电商平台
    • 使用 Supabase 和 Stripe 搭建 SaaS 站点
    • 如何快速搭建公司品牌站点
    • 如何快速搭建博客站点
  • 迁移指南
    • 从 Vercel 迁移至 EdgeOne Makers
    • 从 Cloudflare Pages 迁移至 EdgeOne Makers
    • 从 Netlify 迁移至 EdgeOne Makers
  • 排障指南
  • 常见问题
  • 限制与配额
  • 价格与套餐
  • 联系我们
  • 产品动态

会话管理

Agent 运行在按需拉起、随时会被回收、且同一对话的多次请求可能落在不同实例上的环境里。如果只把数据放在进程内存,会遇到三个绕不开的问题:前端一刷新聊天记录就没了;换了个实例,模型接不上上一轮、表现为「失忆」;审批流、人工介入这类要「等一下再回来」的场景,实例回收后状态就丢了。
context.store 是 Makers Agent 内置的会话管理能力,零配置即可保存与读取对话历史,并为 Claude / OpenAI / LangGraph / DeepAgents Agent 框架提供原生适配。
它的核心特性是跨实例持久化:数据落到平台 Blob 存储,不绑定进程——本次请求写入的数据,在当前请求结束、写入实例被回收、甚至换到另一个实例之后,只要带同一个 conversation_id,新请求仍然读得到。你不用自己管理任何外部数据库或缓存。
说明:
跨实例持久化自 EdgeOne CLI 1.6.26 起支持,请将 CLI 升级到该版本或更高(npm i -g edgeone@latest)。
底层基于平台的 Blob 存储,Node 与 Python 两端 API 完全镜像(JavaScript camelCase、Python snake_case),框架接入章节以 TypeScript 为主,每节附 Python 等价示例。

在两种 Runtime 中使用

storeagents/cloud-functions/ 两类目录的代码中指向同一份数据
目录
使用入口
典型用途
agents/
context.store
LLM 对话主路径,追加消息、Checkpointer
cloud-functions/
context.agent.store
对话列表 API、消息查询

共通前提:对话身份

所有跨实例持久化都以 conversation_id 为 key。你不用自己解析:平台从请求头 makers-conversation-id 解析后注入 context.conversation_id,并在响应头回显 makers-conversation-idmakers-run-id。直接取 context.conversation_id 用即可,不要自己从请求体里另拼一个。对话 ID 作为存储 key 时长度上限 256 字符。

框架接入

context.store 同时提供框架原生适配器通用 API。
framework
推荐用法
入口(TS)
claude-sdk
框架原生 SessionStore
context.store.claudeSessionStore()
openai-sdk
框架原生 Session
context.store.openaiSession(sessionId)
langgraph
框架原生 Checkpointer + BaseStore
context.store.langgraphCheckpointer / .langgraphStore
deepagents
复用 LangGraph Checkpointer + BaseStore
context.store.langgraphCheckpointer / .langgraphStore
crewai
暂不支持,使用通用 API 自管
-

Claude Agent SDK

claudeSessionStore() 返回 SessionStore 协议实现(append / load / listSessions / delete / listSubkeys)。
// typescript
const sessionStore = context.store.claudeSessionStore()

// python
session_store = context.store.claude_session_store()
Claude SDK 的 sessionId 必须是合法 UUID。如果你的 conversation_id 不保证是 UUID(比如 chat-2026-08-12-abc),用 claudeSessionBinding 把它映射成一个稳定的 UUID:本身是 UUID 就原样用,不是就生成一个并持久化映射,同一个 conversation_id 每次都换回同一个 sessionId。
TS 示例:
// agents/chat/index.ts
const conversationId = context.conversation_id ?? ''
const sessionStore = context.store.claudeSessionStore()

// 把任意业务 ID 映射成稳定的 UUID sessionId(是 UUID 就原样返回,否则生成并持久化)
const sessionId = await context.store.claudeSessionBinding(conversationId)

// 判断这个 sessionId 之前有没有落过盘:有就 resume 续上,没有就当新会话
// dir 不能省——SessionStore 的 blob key 按项目目录派生,丢了 dir 永远读不回
const info = await getSessionInfo(sessionId, { dir: process.cwd(), sessionStore })

const options: Record<string, any> = { model, systemPrompt, sessionStore }
if (info) {
options.resume = sessionId // 恢复已有会话
} else {
options.sessionId = sessionId // 新建会话
}

const q = query({ prompt: message, options })
Python 示例:
session_store = context.store.claude_session_store()
session_id = await context.store.claude_session_binding(conversation_id)
# 同样:getSessionInfo 判断 resume/new,options 里带上 session_store 和 resume/session_id
我们提供了示例代码以供参考:Node,Python

OpenAI Agents SDK

openaiSession(sessionId, { maxItems }) 返回 OpenAI Agents SDK 的 Session 协议实现(getItems / addItems / popItem / clearSession)。
// openaiSession 会以 conversation id 为依据自动恢复会话
// typescript
const session = context.store.openaiSession(context.conversation_id)

// python
session = context.store.openai_session(context.conversation_id)
断点续跑(审批流 / human-in-the-loop)要额外用 store.state 上面的 openaiSession 只持久化对话上下文,**不持久化中断时的 RunState**。所以当工具需要人工批准、run() 在中途中断时,要自己把 RunState 序列化存进 context.store.state,下一轮读回、还原、再 run()
// agents/hitl/index.ts
import { RunState, run } from '@openai/agents'
const RUN_STATE_KEY = 'openai.run-state'

// —— 首轮:跑起来,如果中断就把 RunState 存进 state ——
const result = await run(agent, message, { signal })
if (result.state.getInterruptions().length > 0) {
await context.store.state.set(RUN_STATE_KEY, result.state.toString()) // 关键:存 RunState
return json({ status: 'awaiting_approval' })
}
await context.store.state.delete(RUN_STATE_KEY) // 没中断,跑完了,清掉

// —— 下一轮:带批准/拒绝进来,读回 RunState 还原、续跑 ——
const stored = await context.store.state.get<string>(RUN_STATE_KEY)
const state = await RunState.fromString(agent, stored) // 还原中断态
const [approval] = state.getInterruptions()
body.approved ? state.approve(approval) : state.reject(approval)
const resumed = await run(agent, state, { signal }) // 从断点续跑
我们提供了示例代码以供参考:Node,Python

LangGraph

langgraphCheckpointer 实现 BaseCheckpointSavergetTuple / list / put / putWrites),langgraphStore 实现 BaseStoreget / put / search / listNamespaces / batch),BaseStoresearch 暂未支持按语义检索。
// typescript
const checkpointer = context.store.langgraphCheckpointer
const store = context.store.langgraphStore

// python
checkpointer = context.store.langgraph_checkpointer
store = context.store.langgraph_store

DeepAgents

DeepAgents 基于 LangGraph 构建,直接复用 langgraphCheckpointer + langgraphStore 两个适配器。
// typescript
const checkpointer = context.store.langgraphCheckpointer
const store = context.store.langgraphStore

// python
checkpointer = context.store.langgraph_checkpointer
store = context.store.langgraph_store

CrewAI

CrewAI 自带 Memory 强依赖向量库(默认 LanceDB + embedder),context.store暂时未建向量层,对话历史用 context.store通用 API 自管即可,多角色编排、任务链、工具调用等核心能力完全不受影响。
如果需要跨实例恢复会话,每轮结束把框架的会话状态序列化成 JSON 存进去,下一轮开始先读回来还原。只要状态能表达成可 JSON 序列化的对象,就能实现同样的跨实例多轮记忆和断点续跑。典型落地是审批流(human-in-the-loop)——工具调用需人工批准时把运行状态存进 state、返回「等待审批」,下次带同一个 conversation_id(批准或拒绝)读回状态、从断点接着跑,跑完删掉;序列化状态始终只留在服务端。

通用 API

方法总览

方法均挂在 context.store 上。Node 端使用对象解构入参(camelCase),Python 端使用关键字参数(snake_case),语义完全一致。
Node 方法
Python 方法
描述
appendMessage
append_message
追加一条消息;对话不存在时自动创建
getMessages
get_messages
拉消息列表,支持游标分页
updateMessage
update_message
覆盖式更新指定消息
deleteMessage
delete_message
删除单条消息
clearMessages
clear_messages
清空消息但保留对话元信息
getConversation
get_conversation
取对话元信息
listConversations
list_conversations
列对话,按 lastMessageAt 倒序
updateConversation
update_conversation
更新对话元信息,浅合并
deleteConversation
delete_conversation
删除整个对话(不可恢复)
toAnthropicMessages
to_anthropic_messages
把消息列表转成 Anthropic Messages 格式
toOpenAIInput
to_openai_input
把消息列表转成 OpenAI Chat Completions 格式

appendMessage / append_message

向指定对话追加一条消息,对话不存在时自动创建,并按需建立用户索引。
参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
业务侧对话 ID,长度 ≤ 256 字节
role
'user' | 'assistant' | 'system' | 'tool'
Yes
消息角色
content
string | string[] | object
Yes
消息正文,支持纯文本 / 字符串数组 / 多模态 dict,序列化后 ≤ 50MB
metadata
Record<string, any>
No
业务自定义字段(token 数、tool_call、来源标签等)
userId / user_id
string
No
关联用户,传入后写入用户索引,便于按用户列对话
返回值
新消息的 messageId / message_id(形如 msg_xxx)。
TS 示例:
const messageId = await context.store.appendMessage({
conversationId: context.conversation_id,
role: 'user',
content: context.request.body.message,
userId: context.request.body.userId,
metadata: { source: 'web' },
})
Python 示例:
message_id = await context.store.append_message(
conversation_id=context.conversation_id,
role="user",
content=context.request.body["message"],
user_id=context.request.body.get("user_id"),
metadata={"source": "web"},
)

getMessages / get_messages

拉取指定对话的消息列表,支持游标分页。对话不存在不抛异常,返回空列表,默认按时间正序(order='asc',最早优先),方便直接拼 prompt。
参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
limit
number
No
单页条数,默认 20,范围 [1, 100]
order
'asc' | 'desc'
No
排序方向,默认 'asc'(最早优先)
after
string
No
游标,取该 messageId 之后的消息;与 before 互斥
before
string
No
游标,取该 messageId 之前的消息;与 after 互斥
返回值
list[Message] —— 消息数组,对话不存在返回 []
TS 示例:
const messages = await context.store.getMessages({
conversationId: context.conversation_id,
limit: 50,
})
const reply = await openai.chat.completions.create({
model: 'gpt-4o',
messages: context.store.toOpenAIInput(messages),
})
Python 示例:
messages = await context.store.get_messages(
conversation_id=context.conversation_id,
limit=50,
)
reply = await openai_client.chat.completions.create(
model="gpt-4o",
messages=context.store.to_openai_input(messages),
)

updateMessage / update_message

覆盖式更新一条消息,仅传入的字段会被覆盖,未传字段保持原值;updatedAt / updated_at 自动刷新。
参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
messageId / message_id
string
Yes
目标消息 ID
content
string | string[] | object
No
新正文;不传则保持原值
metadata
Record<string, any>
No
整体覆盖 metadata(非合并);不传则保持原值
返回值
Message —— 更新后的完整消息对象。
TS 示例:
const updated = await context.store.updateMessage({
conversationId: context.conversation_id,
messageId: 'msg_abc123',
content: 'corrected answer',
metadata: { edited: true },
})
Python 示例:
updated = await context.store.update_message(
conversation_id=context.conversation_id,
message_id="msg_abc123",
content="corrected answer",
metadata={"edited": True},
)

deleteMessage / delete_message

删除单条消息。

参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
messageId / message_id
string
Yes
目标消息 ID
TS 示例:
await context.store.deleteMessage({
conversationId: context.conversation_id,
messageId: 'msg_abc123',
})
Python 示例:
await context.store.delete_message(
conversation_id=context.conversation_id,
message_id="msg_abc123",
)

clearMessages / clear_messages

清空对话中所有消息,但保留 ConversationMeta,彻底删除请用 deleteConversation
参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
TS 示例:
await context.store.clearMessages({ conversationId: context.conversation_id })
Python 示例:
await context.store.clear_messages(conversation_id=context.conversation_id)

getConversation / get_conversation

获取对话元信息。
参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
返回值
ConversationMeta —— 包含 conversationId / createdAt / lastMessageAt / messageCount / metadata 等字段。
TS 示例:
const meta = await context.store.getConversation({
conversationId: context.conversation_id,
})
console.log(meta.messageCount, meta.metadata?.title)
Python 示例:
meta = await context.store.get_conversation(
conversation_id=context.conversation_id,
)
print(meta.message_count, (meta.metadata or {}).get("title"))

listConversations / list_conversations

列对话,按 lastMessageAt 排序,支持游标分页与按用户过滤。

参数
Parameter
Type
Required
Description
limit
number
No
单页条数,默认 20,范围 [1, 100]
order
'asc' | 'desc'
No
排序方向,默认 'desc'(最新优先)
after
string
No
游标,传上一页返回的 nextCursor
before
string
No
游标,传上一页返回的 previousCursor
userId / user_id
string
No
仅列该用户名下的对话(命中用户索引)
返回值
ListConversationsResult —— { items, nextCursor, previousCursor }

TS 示例:
const { items, nextCursor } = await context.store.listConversations({
userId: 'u_123',
limit: 20,
})
Python 示例:
result = await context.store.list_conversations(user_id="u_123", limit=20)
items, next_cursor = result.items, result.next_cursor

updateConversation / update_conversation

浅合并 metadata:同 key 覆盖、不同 key 保留。
参数
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
metadata
Record<string, any>
Yes
待合并字段;value 为 null / None 表示删除该 key
返回值
ConversationMeta —— 合并后的对话元信息。
TS 示例:
await context.store.updateConversation({
conversationId: context.conversation_id,
metadata: { title: '产品咨询', tag: null }, // 设标题,删 tag
})
Python 示例:
await context.store.update_conversation(
conversation_id=context.conversation_id,
metadata={"title": "产品咨询", "tag": None},
)

deleteConversation / delete_conversation

删除整个对话,同步清理消息索引、会话元信息和全局会话索引,不可恢复
参数:
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
对话 ID
TS 示例:
await context.store.deleteConversation({
conversationId: context.conversation_id,
})
Python 示例:
await context.store.delete_conversation(
conversation_id=context.conversation_id,
)

toAnthropicMessages / to_anthropic_messages

getMessages 返回的消息列表转成 Anthropic Messages API 的 messages 字段格式。
参数
Parameter
Type
Required
Description
messages
Message[]
Yes
getMessages / get_messages 的返回结果
返回值
Array<{ role: string; content: unknown }>—— 可直接作为 anthropic.messages.create({ messages }) 的入参。
TS 示例:
const history = await context.store.getMessages({
conversationId: context.conversation_id,
})
const resp = await anthropic.messages.create({
model: 'claude-sonnet-4',
max_tokens: 1024,
messages: context.store.toAnthropicMessages(history),
})
Python 示例:
history = await context.store.get_messages(
conversation_id=context.conversation_id,
)
resp = await anthropic_client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
messages=context.store.to_anthropic_messages(history),
)

toOpenAIInput / to_openai_input

getMessages 返回的消息列表转成 OpenAI Chat Completions API 的 messages 字段格式,保留 roleuser / assistant / system / toolcontent 透传。
参数
Parameter
Type
Required
Description
messages
Message[]
Yes
getMessages / get_messages 的返回结果
返回值
Array<{ role: string, content: any }> —— 可直接作为 openai.chat.completions.create({ messages }) 的入参。
TS 示例:
const history = await context.store.getMessages({
conversationId: context.conversation_id,
})
const resp = await openai.chat.completions.create({
model: 'gpt-4o',
messages: context.store.toOpenAIInput(history),
})
Python 示例:
history = await context.store.get_messages(
conversation_id=context.conversation_id,
)
resp = await openai_client.chat.completions.create(
model="gpt-4o",
messages=context.store.to_openai_input(history),
)

state — 通用状态存储

前面的方法都是围绕「消息」的。context.store.state 是另一类能力:一个按对话隔离的 JSON 键值存储,存什么由你决定。适合任何框架,尤其是没有原生适配器的框架(如 CrewAI)、以及要存业务自定义状态(步骤计数、临时变量、序列化后的框架运行状态)的场景。
conversationId 自动绑定当前对话,方法上不用再传,写入按 conversationId 命名空间隔离。和消息历史、会话上下文一样,state 里的值也是跨实例持久化的——换实例读同一个 conversationId 仍在。
Node 方法
Python 方法
描述
state.get(key)
state.get(key)
读取;key 不存在返回 null / None
state.set(key, value)
state.set(key, value)
写入;value 必须 JSON 可序列化
state.delete(key)
state.delete(key)
删除该 key
三个方法均为异步。
参数与约束
说明
key
字符串,长度 1–256
value
必须 JSON 可序列化:null / 字符串 / 布尔 / 有限数字 / 普通对象 / 数组。函数、循环引用、NaN / Infinity 会被拒绝
TS 示例:
// 请求开始:读回上一轮状态(没有则 null)
const saved = await context.store.state.get<MyState>('session')

// ... 跑一轮对话 ...

// 请求结束:把最新状态存回去
await context.store.state.set('session', latestState)
Python 示例:
saved = await context.store.state.get("session")
# ... 跑一轮 ...
await context.store.state.set("session", latest_state)
通用做法:用其他框架实现多轮记忆 / 断点续跑。 没有原生适配器时,思路是每轮结束把框架的会话状态序列化成 JSON 存进 state,下一轮开始先读回来还原。只要状态能表达成可 JSON 序列化的对象,就能实现跨进程的多轮记忆和断点续跑,不依赖任何框架特定的适配器。一个典型落地是审批流(human-in-the-loop):工具调用需要人工批准时,把框架序列化出的运行状态存进 state,返回「等待审批」;下一次带同一个 conversationId 进来(批准或拒绝),读回状态、从断点接着跑,跑完删掉。序列化的状态始终只留在服务端,前端只发消息和「批准/拒绝」的决定。

数据结构

interface Message {
messageId: string // msg_xxx(appendMessage 自动生成)
role: 'user' | 'assistant' | 'system' | 'tool'
content: any // string / array / object(多模态)
createdAt: number // ms 时间戳
metadata?: Record<string, any> // 自定义(token 数、tool_call 等)
updatedAt?: number // 仅 updateMessage 后存在
}

interface ConversationMeta {
conversationId: string
createdAt: number // ms 时间戳
lastMessageAt: number // ms 时间戳
messageCount: number
metadata?: Record<string, any> // 业务自定义(标题、用户、标签等)
}

interface ListConversationsResult {
items: ConversationMeta[]
nextCursor?: string // 下一页游标,传给 after 参数
previousCursor?: string // 上一页游标,传给 before 参数
}
Python 端字段为 message_id / conversation_id / created_at / last_message_at / message_count / next_cursor / previous_cursor,整体形态一致。

限制与配额

默认
超限行为
conversation_id 长度
≤ 256 字符
MemoryValidationError
单条 content 大小
≤ 50MB(序列化后)
MemoryValidationError
单对话最大消息数
10000
MemoryQuotaExceededError
limit 上限
100
MemoryValidationError
limit 下限
1
MemoryValidationError
单条 content 超大(长文档、图片原始数据)建议放对象存储,传 URL 进消息。

对话摘要

getMessages 单次最多取 100 条,长对话下推荐做法是保留最近 N 条原文 + 早期内容压成一段摘要,每次请求时从 Store 拼装回 prompt。Store 本身不调 LLM、不生成摘要,只提供 ConversationMeta.metadata 这个 JSON 容器。

职责切分

谁负责
做什么
Store
提供 metadata JSON 字段 + 浅合并写入。约定两个 key:summary(摘要文本)、summarizedUntil(已摘要到哪条 messageId
业务侧
决定何时摘要、调便宜模型生成摘要、调 updateConversation 写回
summary / summarizedUntil约定 key 而非 schema,Store 只把它当任意 JSON 存。你可以换名字,只要业务侧前后保持一致。

实现示例

可以使用便宜模型做摘要——压缩 + 保关键事实不需要主模型那种推理能力。prompt 中四条要求都不能省,否则会出现摘要发散、寒暄混入、语言乱跳、越摘越长等问题。
async function summarizeWithLLM(previousSummary, newMessages) {
const transcript = newMessages
.filter(m => m.role === 'user' || m.role === 'assistant')
.map(m => `${m.role}: ${
typeof m.content === 'string' ? m.content : JSON.stringify(m.content)
}`)
.join('\n')
const prompt = previousSummary
? `下面是一段对话的【已有摘要】和【新增对话】,请合并成一段新摘要。
要求:
- 保留:关键事实、用户偏好、未完成的任务、重要的上下文设定
- 删除:寒暄、确认收到、重复内容、工具调用细节
- 用与最近对话相同的语言书写
- 控制在 500 字内

【已有摘要】
${previousSummary}

【新增对话】
${transcript}

【新摘要】`
: `请把下面的对话总结成一段摘要。
要求:
- 保留:关键事实、用户偏好、未完成的任务、重要的上下文设定
- 删除:寒暄、确认收到、重复内容、工具调用细节
- 用与对话相同的语言书写
- 控制在 500 字内

【对话】
${transcript}
【摘要】`
const { text } = await generateText({
model: openai('gpt-4o-mini'),
prompt,
maxTokens: 800,
})
return text.trim()
}

消息存储和会话上下文存储的区别

context.store 上有两类互相独立、不能互相替代的持久化,多数对话应用两个都要:
存哪种
管什么效果
怎么存
消息历史
前端刷新后聊天记录还在、能重新渲染,侧边栏能列历史会话
通用 API appendMessage / getMessages,是纯读写、不调模型的数据
会话上下文
模型记得上一轮说了什么(多轮连续对话)、中断能续跑
交给框架原生适配器(见「跨实例恢复会话」),框架自己按原生格式读写
两个最常见的误区:
只写了消息历史、没接会话上下文/history 里看得到记录,但模型每轮都失忆,因为上下文没喂回给它。
只接了会话上下文、没写消息历史 → 模型记得住,但前端一刷新聊天记录空白,因为框架的 session 格式不是给前端渲染用的。
一句话:消息历史管「刷新后看得见」,会话上下文管「模型记得住」,各管一摊,都是跨实例持久化的。