TencentDB-Agent-Memory Opik 历史数据导入:将 Opik Trace 一键迁移至 Memory Core L0
2026/9/11 11:52:46 网站建设 项目流程

TencentDB-Agent-Memory Opik 历史数据导入:将 Opik Trace 一键迁移至 Memory Core L0

【免费下载链接】TencentDB-Agent-MemoryTencentDB Agent Memory is a team-level memory hub for AI Agents — turning conversations, docs, and code into four reusable memory assets (Chat Memory, Skill, LLM-Wiki, Code-Graph) that are governed, shared, and equipped across agents and frameworks.项目地址: https://gitcode.com/GitHub_Trending/te/TencentDB-Agent-Memory

导读

本指南围绕 TencentDB-Agent-Memory 仓库中MemoryCore/scripts/import-opik-to-memory-core工具,完整讲解如何把 Opik 平台上已有的 Project Trace 批量转换为对话消息,并通过 Memory Core Gateway 的POST /v3/conversation/add写入 L0 层。读完本文,你将掌握:从环境变量安全配置 Opik 与 Memory Core 地址、Dry Run 预演、断点续传、Pipeline 节流到回查校验的一整套可落地的历史数据迁移方案,同时了解工具底层如何解析常见 Trace 结构、合并 input/output 消息并稳定生成 session_id。

工具定位:把可观测平台沉淀的对话搬进记忆系统

Opik(Comet 开源的 LLM 可观测平台)会以 Trace 形式记录每次 LLM 调用的input/output,其中往往完整保存了用户与模型的对话。当团队从其他框架或自建链路迁移到 TencentDB-Agent-Memory 时,这些历史对话正是最有价值的记忆资产——它们对应 Memory Core 四层记忆体系中的 L0 原始对话流水(Raw Conversation)。

本工具(index.ts)扮演“数据搬运工”角色:

  • 从 Opik 私有 API(/api/v1/private分页读取全部 Project 与指定 Project 的全部 Trace;
  • 从 Trace 的input/output自动识别并抽取对话消息,规范化为{ role, content, timestamp }结构;
  • 通过 Memory Core Gateway 的POST /v3/conversation/add写入 L0,并带上team_id/agent_id/user_id/service_idx-tdai-service-id)等隔离字段,使历史对话进入与线上链路一致的租户隔离与后续 L1 抽取流程。

从工具入口看,命令注册在 package.json 的import:opikscript,实际执行体是tsx scripts/import-opik-to-memory-core/index.ts,要求 Node.js>= 22.16.0

前置条件与快速查看帮助

开始前需要满足以下前提:

  • Node.js>= 22.16.0,且已安装当前项目依赖(在 MemoryCore/package.json 中声明);
  • Opik REST API 可访问;
  • 远端 Memory Core Gateway 可访问/health/v3/conversation/add/v3/conversation/query
  • 已确定目标service_idteam_idagent_iduser_id(如需要还可指定task_id)。

进入 Memory Core 目录后即可查看全部参数:

cd MemoryCore npm run import:opik -- --help

从源码的usage()(index.ts)可以看到参数分为四组:数据源(Opik)、目标(Memory Core)、执行控制、密钥环境变量。命令使用 Node 内置node:utilparseArgs解析,strict: true模式下未知参数会直接报错(index.ts)。

配置 Opik 地址与分页读取

推荐只配置 Opik 根地址和 workspace:

export OPIK_URL='http://opik.example.com:5173' export OPIK_WORKSPACE='default'

也兼容直接粘贴 UI 地址:

http://opik.example.com:5173/default/projects?size=25

关于 UI URL 有两个关键点(源码parseOpikBase实现,index.ts):

  1. UI URL 中的size=25不会限制导入范围——工具会把 URL 规范化并转换成/api/v1/privateAPI 地址,size参数被清除,分页读取与页面展示无关;
  2. URL 首段若既不是api也不是v1,会被识别为 workspace(例如上面的default);显式传入--workspace或设置OPIK_WORKSPACE优先级更高。

分页策略在OpikClient(index.ts)中实现:projects()traces()均从page=1起循环拉取,直到已读数量 >= total或某页为空才停止,--page-size默认100。Trace 读取时还会带上truncate=falsestrip_attachments=true,前者保证拿到完整 input/output,后者剥离附件减少无效数据;最终 Trace 按start_time(回退到created_at)升序排序,保证导入顺序与对话发生顺序一致。

另外注意:OPIK_URL中不允许携带用户名/密码(parseOpikBase会直接抛错),凭据必须通过环境变量传递。

配置远端 Memory Core 与鉴权

以下地址仅为示例,请替换成实际 Gateway 地址:

export MEMORY_CORE_URL='http://memory-core.example.com:8423' export MEMORY_CORE_SERVICE_ID='default' export MEMORY_CORE_TEAM_ID='team-001' export MEMORY_CORE_AGENT_ID='agent-001' export MEMORY_CORE_USER_ID='user-001'

可选 Task 隔离:

export MEMORY_CORE_TASK_ID='task-001'

不需要 Task 时:

unset MEMORY_CORE_TASK_ID

安全输入 API Key,避免写入代码或配置文件:

read -s "MEMORY_CORE_API_KEY?Memory Core API Key: " echo export MEMORY_CORE_API_KEY

检查 Gateway 连通性:

curl --fail --silent --show-error "${MEMORY_CORE_URL}/health"

源码层面,MemoryCoreClient(index.ts)对每次写请求固定携带以下 Header:

  • Authorization: Bearer ${MEMORY_CORE_API_KEY}
  • x-tdai-service-id:来自MEMORY_CORE_SERVICE_ID,标识服务实例;
  • Content-Type: application/json

MEMORY_CORE_API_KEY在非 Dry Run 模式下为必填,缺少会直接报错退出(index.ts)。响应采用统一信封{ code, message, request_id, data }结构,code !== 0视为失败并携带request_id便于排查;成功时以data.accepted_ids.length(回退data.total_count)作为该批实际接收数,并与本批消息数比对,不一致即中止,防止静默丢数据(index.ts)。

先执行 Dry Run 验证

Dry Run 会读取真实 Opik 并转换 Trace,但不会写入 Memory Core 或断点文件:

npm run import:opik -- \ --project '5d0fd72d' \ --max-traces 5 \ --dry-run

--project同时接受 Project 名称和 UUID,可以重复传入或使用逗号分隔:

npm run import:opik -- \ --project 'project-a' \ --project '019fb2e2-16a9-717d-98a8-0cd2e1bef87e' \ --dry-run

不传--project会处理 workspace 下全部项目。项目数量较多时,应先指定项目和--max-traces做小批验证。

Dry Run 时每条 Trace 会打印一行[dry-run] project=... trace=... session=... batch=... messages=...,可以直观看到“一个 Trace 被拆成几个批次、每批几条消息”,并且--dry-run模式不要求MEMORY_CORE_API_KEY(index.ts),适合在目标环境未就绪时先行验证解析效果。

Trace 消息解析原理

工具的核心竞争力在于兼容多种常见的 Trace 结构。入口函数extractMessages(index.ts)的实现分两条路径:

路径一:识别消息数组。findMessageArrays(index.ts)在input/output中深度优先(最多 5 层)寻找“看起来像消息数组”的结构——数组内任一元素包含role字段(或元素.message 内含 role)。命中后优先按messagesconversationhistory这三个键名查找,找不到再遍历对象所有值兜底。随后bestMessageArray对所有候选数组统一规范化后选取消息数量最多的一组,避免误命中子对象里的零散消息。

**路径二:prompt/response 兜底。**若找不到消息数组,则分别从 input 的userPromptuser_promptpromptqueryinputcontenttext等键提取 prompt,从 output 的responseContentanswerresponsecompletionoutputcontenttext等键提取 answer,各生成一条 user/assistant 消息(index.ts)。

角色归一化normalizeRole):user/human→ user;assistant/ai/model/bot→ assistant;仅在开启--include-system时,system/developer才会以带前缀(如[system])的 user 消息导入(index.ts)。

内容提取contentToText)兼容字符串、{ type: "text", text }结构块、OpenAIchoices[].message等多态形式(index.ts)。

input/output 合并mergeMessages通过检测 input 消息尾部与 output 消息头部的最大重叠(相同 role + 相同 content)来消除重复——很多 Agent 框架的 output 会回显完整上下文,这一步保证最终会话不出现重复轮次(index.ts)。

大小限制:单条消息超过MAX_MESSAGE_CHARS = 8192字符会被splitContent按字符边界(并避开 UTF-16 代理对截断)拆分;单次请求最多MAX_MESSAGES_PER_REQUEST = 100条消息,超出部分自动chunk成多个批次(index.ts)。

正式导入与 session_id 生成

Dry Run 确认解析无误后执行正式导入:

npm run import:opik -- \ --project '5d0fd72d' \ --max-traces 5 \ --state-file './opik-import-remote-state.json'

成功时会输出:

[import] project=... trace=... accepted=... [done] seen_traces=5 imported_traces=5 ... imported_messages=...

工具实际调用:

POST <MEMORY_CORE_URL>/v3/conversation/add

写入范围由以下字段共同决定:

  • x-tdai-service-id:MEMORY_CORE_SERVICE_ID
  • team_id:MEMORY_CORE_TEAM_ID
  • agent_id:MEMORY_CORE_AGENT_ID
  • user_id:MEMORY_CORE_USER_ID
  • task_id:MEMORY_CORE_TASK_ID,可选
  • session_id: 根据 Opik Project ID 和thread_id/Trace ID 稳定生成

session_id的生成规则在buildSessionId(index.ts)中:优先使用 Trace 的thread_id(Opik 中同一条会话线程会共享 thread_id),缺失时回退到 Trace ID;随后做「可读化 + 哈希稳定化」——可读部分取前 48 字符并替换非法字符,再拼上 source 的 SHA-256 前 12 位,最终形如opik:<project_id>:<readable>:<hash12>。这样的设计保证:同一线程的 Trace 落在同一 session_id,重复执行不产生新会话,且不会与其他来源的 session 冲突

Gateway 侧,/v3/conversation/add是强隔离覆盖路径之一(见 v2-router.ts 的V3_ALLOWED_SUBPATHS),请求体与响应契约见 v2-schemas.ts:session_id缺省时自动落到默认兼容桶DEFAULT_ISOLATION_IDmessages数组 1~100 条。写入 L0 后,Gateway 会通过notifyPipeline触发异步 L1 抽取(v2-router.ts),历史对话随即进入与实时链路一致的记忆提取流程。

断点续传:重复执行自动跳过已完成批次

默认启用断点续传。每个成功批次会立即写入--state-file,重新执行相同命令时自动跳过已完成批次:

npm run import:opik -- \ --project '5d0fd72d' \ --state-file './opik-import-remote-state.json'

忽略已有断点:

npm run import:opik -- \ --project '5d0fd72d' \ --no-resume

--no-resume可能造成重复导入,只应在明确需要重新导入时使用。

实现细节(index.ts):

  • 断点文件默认.opik-memory-import-state.json,格式为{ version: 1, completed: { "<checkpointKey>": { imported_at, accepted } } }version不匹配会拒绝加载;
  • 断点键为project_id:trace_id:<batch 内容哈希>:<批次序号>(index.ts),批次内容哈希由 SHA-256 截取 20 位生成,因此消息内容变化会形成新断点键,天然避免内容漂移导致的重复或漏导;
  • 每个批次成功写入后立即原子落盘(先写state-file.tmp-<pid>再 rename),文件权限0600,即使中途中断也不丢进度;断点文件不保存 API Key,可安全纳入版本控制或归档;
  • 失败场景下,Memory Core 接收数量与批次不符会直接抛错中止(而非标记断点),保证断点只记录“真实成功”的批次。

Pipeline 节流:等待 L1/L2/L3 空闲

默认每写入 20 个批次等待 L1 空闲,并在结束时等待 L1/L2/L3 全部空闲:

npm run import:opik -- \ --project '5d0fd72d' \ --wait-every 20 \ --state-file './opik-import-remote-state.json'

如果目标环境关闭了记忆提取、只需要写 L0:

npm run import:opik -- \ --project '5d0fd72d' \ --wait-every 0 \ --no-final-wait \ --state-file './opik-import-remote-state.json'

节流由MemoryCoreClient.waitForIdle(index.ts)实现:轮询POST /v2/pipeline/status,读取各层{ idle, queued, running }状态;l1模式只看 L1,all模式要求 L1/L2/L3 全空闲。轮询间隔--poll-ms(默认1000)与单次等待上限--max-wait-ms(默认600000,即 10 分钟)均可调。等待超时不会失败,只是告警“导入数据已落 L0,后台将继续处理”——因为 L0 是持久化流水,后台抽取异步完成,超时不影响数据完整性。需要注意/v2/pipeline/statusstandalone 单机模式才开放的端点(v2-router.ts 注释明确 service 模式返回 404),因此在多租户 service 部署下应使用--wait-every 0 --no-final-wait

回查导入结果

写入完成后,用/v3/conversation/query按隔离维度回查:

curl --fail --silent --show-error \ -X POST "${MEMORY_CORE_URL}/v3/conversation/query" \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer ${MEMORY_CORE_API_KEY}" \ -H "x-tdai-service-id: ${MEMORY_CORE_SERVICE_ID}" \ --data "$(cat <<JSON { "team_id": "${MEMORY_CORE_TEAM_ID}", "agent_id": "${MEMORY_CORE_AGENT_ID}", "user_id": "${MEMORY_CORE_USER_ID}", "limit": 100, "offset": 0 } JSON )"

team_id/agent_id/user_id三者为查询隔离维度,也可传入session_id精确限定某条会话(session_id可选,缺省时按 (team, agent, user) 聚合查询,见 v2-router.ts 注释)。对比返回条数与导入的imported_messages,即可确认全量落库。

Opik 鉴权配置

自托管 Opik 默认可能不需要鉴权。启用鉴权时:

read -s "OPIK_API_KEY?Opik API Key: " echo export OPIK_API_KEY export OPIK_AUTH_SCHEME='Bearer'

OPIK_AUTH_SCHEME为空时,OPIK_API_KEY会原样作为AuthorizationHeader。源码在OpikClient.headers()(index.ts)中实现:请求始终携带Comet-Workspace-Name(即 workspace,Comet/Opik 服务端用它识别租户),鉴权存在时拼接scheme + ' ' + key或裸 key。注意 OPIK 与 MEMORY_CORE 是两套独立的密钥体系,切勿混用。

常用参数一览

参数默认值说明
--project全部项目Project 名称或 UUID,可重复或逗号分隔
--page-size100Opik API 每页数量
--max-traces0本次最多处理的 Trace 数,0表示不限
--state-file.opik-memory-import-state.json断点文件
--dry-run关闭只拉取和转换,不写入
--no-resume关闭忽略断点,可能重复导入
--include-system关闭将 system/developer 转成带前缀的 user 消息
--wait-every20每 N 个写请求等待 L1,0禁用
--no-final-wait关闭不等待最终 L1/L2/L3 空闲
--timeout-ms30000单次 HTTP 请求超时
--retries4网络错误、429 和 5xx 重试次数

表格之外,从usage()parseCli还可以看到两个未在 README 表格中列出的节流参数:--poll-ms(Pipeline 轮询间隔,默认1000)与--max-wait-ms(单次等待上限,默认600000),以及对应的命令行等价物:--opik-url--memory-url--workspace--team-id--agent-id--user-id--task-id--service-id,它们与同名环境变量二选一即可(命令行优先)。

重试与网络容错

HttpClient.json(index.ts)实现了指数退避重试:对网络错误、HTTP 429(限流)和 5xx(服务端错误)最多重试--retries(默认 4)次,退避间隔为min(1000 * 2^attempt, 10000) + 随机 0~250ms抖动;而 4xx 除 429 外(如 401/403/400)属于NonRetryableHttpError,直接抛出不浪费重试。每个请求通过AbortController--timeout-ms(默认 30000ms)后中止。该重试策略同时作用于 Opik 读取与 Memory Core 写入,配合断点机制,能在网络抖动场景下安全完成大规模导入。

已验证链路与最佳实践

官方文档记录该工具已使用真实 Opik API 和隔离的本地 Memory Core 完成端到端验证:

  1. 分页读取 Opik Project 和 Trace
  2. 将 5 个 Trace 转换为 15 条 L0 消息
  3. 写入/v3/conversation/add
  4. 通过/v3/conversation/query回查 15 条消息
  5. 重复执行时断点命中、写入数为 0
  6. SQLite 与 JSONL 镜像落盘数量一致

综合上述机制,生产环境推荐的导入流程是:

  1. 小批预演--project <name> --max-traces 5 --dry-run,确认消息抽取符合预期(查看[dry-run]行数与 session 分布);
  2. 首次全量:指定--state-file(建议放在单独目录),不传--max-traces或按需设置,配合默认节流参数;
  3. 中断恢复:直接重跑同一条命令,断点自动跳过已完成批次;
  4. 校验/v3/conversation/query分页回查数量与imported_messages一致;
  5. 特殊数据:需要保留 system 提示词时加--include-system,service 多租户部署下使用--wait-every 0 --no-final-wait

在整个过程中,所有密钥(OPIK_API_KEYMEMORY_CORE_API_KEY)均只从环境变量读取,工具的parseOpikBase甚至禁止在 URL 中携带凭据,从源头规避了密钥落入命令历史或配置文件的泄露风险。

【免费下载链接】TencentDB-Agent-MemoryTencentDB Agent Memory is a team-level memory hub for AI Agents — turning conversations, docs, and code into four reusable memory assets (Chat Memory, Skill, LLM-Wiki, Code-Graph) that are governed, shared, and equipped across agents and frameworks.项目地址: https://gitcode.com/GitHub_Trending/te/TencentDB-Agent-Memory

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询