DeerFlow 接入 OpenViking 长期记忆后端:认证边界、配置全解与失败语义
本文以 docs/OPENVIKING.md 为主体,完整讲解 DeerFlow 的 OpenViking 长期记忆后端:如何用 USER API Key 配置 manager_class: openviking、如何启动并验证 OpenViking 服务、线程到 Session 的确定性映射规则,以及读取/写入失败策略、哈希游标与优雅关闭的底层实现。读完后你可以独立完成该后端的部署配置,并从源码层面理解其身份隔离与数据一致性边界。
OpenViking 后端定位与当前范围
DeerFlow 支持把远程 OpenViking 服务器作为可选的长期记忆后端,默认后端仍是 DeerMem。该后端不自行实现 OpenViking 的 HTTP 协议,而是直接使用官方维护的 langchain-openviking 适配包(仓库中以 langchain-openviking==0.1.0 锁定,声明在 harness 包依赖 中,通过常规 uv sync 流程安装)。
首个官方适配器集成刻意保留 DeerFlow 现有的自动记忆行为:
- 记忆通过 DeerFlow 既有的固定记忆查询(fixed memory query)召回;
- 已完成的轮次由现有 memory middleware 捕获;
- 即将被压缩(compaction)的消息由现有 summarization hook 捕获;
- 每条被接受的捕获都提交到该线程稳定的 OpenViking Session;
- 消息转换、工具调用与结果处理、100 条消息分批、部分写入进度记录、提交重试和 SDK 传输全部由官方适配器负责;
- 一个由 recorder 拥有的 SDK 客户端与检索共享,并通过 DeerFlow 既有的 memory 关闭契约统一关闭。
明确的范围边界(这些不是缺陷,而是有意为之):
- 仅支持
memory.mode: middleware。在 OpenVikingMemoryManager.from_config 中,mode != "middleware"会直接抛出ValueError,并提示需要模型主动调用记忆工具时应走 OpenViking MCP; - 不实现 DeerMem 的 fact CRUD、导入/导出,也不提供 Settings 中的记忆文档视图;
- OpenViking MCP 工具是另一个独立的集成面,不由该后端启用(见 extensions_config.example.json 中默认
enabled: false的openvikingMCP 条目)。
认证边界:一个 USER Key 绑定一个 DeerFlow 用户
api_key 模式是唯一支持的服务器配置
当前版本面向「一个 DeerFlow 用户 + 一个普通 OpenViking USER API Key」的部署形态。OpenViking 从该凭据推导 account 和 user;DeerFlow 不配置 trusted account/user 请求头,正常记忆流量也不应持有 root key。
支持的服务端配置是 OpenViking 的 api_key 模式:DeerFlow 显式提供 URL 与 API Key,在记忆操作中覆盖任何环境里的 actor peer,且不继承 ovcli.conf 中的任意 HTTP 头。源码中这一点有明确对应:OpenVikingMemoryManager 构造 recorder 时传入 extra_headers={},注释写明该显式映射会禁用 SDK 的 ovcli.conf 头回退;每次操作再用 use_actor_peer 作用域覆盖环境身份。
启用该后端前的清理清单:
- 从 DeerFlow 仓库根
.env和服务环境中移除遗留的OPENVIKING_ACCOUNT、OPENVIKING_USER; - 从
~/.openviking/ovcli.conf移除account、user默认值。
这些设置属于 trusted 模式,不在本适配器的支持范围内。
配置校验在启动期就会拦截遗留字段:OpenVikingConfig.from_backend_config 检测到 auth_mode 或 account 字段会直接抛错("trusted mode is no longer supported"),自定义 HTTP 客户端字段(如 connect_timeout_seconds、max_retries 等)同样被拒。
owner_user_id:防止一个 Key 被多个用户共享
owner_user_id 把配置好的 Key 绑定到一个 DeerFlow 身份:DeerFlow 认证关闭时用 default;启用认证的单用户部署填该用户的 DeerFlow ID。请求属于其他 DeerFlow 用户时,会在联系 OpenViking 之前被拒绝,避免一个 USER Key 在用户之间静默共享记忆。
源码中的强制点在 _resolve_scope:
resolved_user = str(user_id or "default")
if resolved_user != self._config.owner_user_id:
raise MemoryManagerError(
f"OpenViking USER API key is bound to DeerFlow owner_user_id "
f"{self._config.owner_user_id!r}, but this request belongs to "
f"{resolved_user!r}. Refusing to share one credential across users."
)
多用户的凭据供给与存储被有意排除在第一个适配器之外。
旧 trusted 模式配置不会自动迁移
现有 trusted 模式配置不会被自动迁移。需要把 OpenViking 服务器配置为 api_key 模式,用 owner_user_id + USER Key 替换 auth_mode、account 和 root key,并移除上述遗留环境身份设置。由于凭据绑定的 user/Session 映射与旧的 trusted-user 映射不同,先前捕获的 trusted 模式数据会留在其旧的 OpenViking 命名空间中,不会被静默重分配。
配置 DeerFlow
第一步:写入 .env 与 config.yaml
在 OpenViking 中创建或选择用户,把其 USER API Key 写入 DeerFlow 仓库根 .env:
OPENVIKING_API_KEY=replace-with-an-openviking-user-api-key
在 config.yaml 中选择后端:
memory:
enabled: true
injection_enabled: true
shutdown_flush_timeout_seconds: 30
manager_class: openviking
mode: middleware
backend_config:
base_url: http://127.0.0.1:1933
owner_user_id: default
api_key_env: OPENVIKING_API_KEY
startup_policy: fail_fast
failure_policy:
read: fail_open
write: log_and_drop
retrieval:
top_k: 8
score_threshold: 0.25
max_injection_chars: 12000
content_mode: overview
injection_query: >-
user profile preferences important entities events ongoing goals
constraints and prior decisions
同一份示例也内嵌在 config.example.yaml 的 memory 配置注释区(manager_class: openviking 时替换默认 DeerMem 的 backend_config 块)。
backend_config 完整参数表(源码校验值)
下表由 OpenVikingConfig 的默认值与 _validate() 取值范围整理,可复制到实际配置中使用:
| 参数 | 默认值 | 取值范围 / 说明 |
|---|---|---|
base_url |
http://127.0.0.1:1933 |
必须是绝对 http(s) URL;纯 HTTP 仅允许 127.0.0.1 / localhost / openviking,其他主机必须 HTTPS 或显式 allow_insecure_http: true |
owner_user_id |
必填,无默认 | 绑定 Key 的 DeerFlow 用户 ID;认证关闭时用 default;空值启动失败 |
api_key_env |
OPENVIKING_API_KEY |
存放 USER Key 的环境变量名;Key 缺失时启动失败(fail_fast 语义) |
default_peer_id |
deerflow |
默认 agent 的 OpenViking peer ID;必须匹配 ^[a-z0-9][a-z0-9_-]{0,63}$,且不得以保留前缀 df-agent- 开头 |
timeout_seconds |
30.0 |
必须为 > 0 的有限数值 |
storage_path |
空(用 DeerFlow base_dir) | 本地哈希游标根目录前缀 |
startup_policy |
fail_fast |
fail_fast 或 warn;控制启动期健康检查失败是否直接抛错 |
failure_policy.read |
fail_open |
fail_open(记日志并返回无注入记忆)或 raise(向调用方传播) |
failure_policy.write |
log_and_drop |
log_and_drop(记日志,不使已生成的回答失败)或 raise |
allow_insecure_http |
false |
受信内网下才置 true |
max_seen_message_ids |
512 |
有界哈希游标容量,范围 16–10000 |
retrieval.top_k |
8 |
1–100 |
retrieval.score_threshold |
无阈值(null) |
0–1 的有限数值 |
retrieval.max_injection_chars |
12000 |
256–100000 |
retrieval.content_mode |
overview |
auto / abstract / overview / read |
retrieval.injection_query |
与上文示例相同 | 固定记忆查询,不得为空 |
此外,任何未识别的 backend_config 顶层字段、retrieval.* 或 failure_policy.* 字段都会触发启动期报错(config.py#L98-L106),可以防止拼写错误被静默忽略。
宿主安装 vs Docker 部署的地址差异
- 宿主安装 OpenViking、Docker 运行 DeerFlow:
base_url设为http://host.docker.internal:1933,并配allow_insecure_http: true; - 使用仓库自带的可选 Compose overlay 时,走容器网络内部地址
http://openviking:1933(该主机名在纯 HTTP 白名单内,无需allow_insecure_http)。
启动服务
本地进程:先起 OpenViking 并验证
openviking-server doctor
openviking-server
curl http://127.0.0.1:1933/health
随后正常启动 DeerFlow:
make doctor
make dev
DeerFlow 位于 http://localhost:2026,OpenViking Studio 位于 http://localhost:1933/studio(可在 Studio 中人工检查记忆捕获与 Session 归档)。
Docker:可选 Compose overlay
docker compose \
-f docker/docker-compose.yaml \
-f docker/docker-compose.openviking.yaml \
up -d openviking
docker exec -it deer-flow-openviking openviking-server init
docker compose \
-f docker/docker-compose.yaml \
-f docker/docker-compose.openviking.yaml \
up -d --build
overlay 文件 的关键点:镜像默认 ${OPENVIKING_IMAGE:-ghcr.io/volcengine/openviking:latest},以 --without-bot 启动,端口映射 ${OPENVIKING_PORT:-1933}:1933,数据卷 openviking-data 挂到容器内 /app/.openviking;健康检查通过 /health 探测,且 gateway 服务 depends_on: openviking: condition: service_healthy——即 OpenViking 不就绪时 gateway 不会被拉起。
启动后把 OpenViking 配置为 API-key 模式,通过其身份管理流程获取 USER Key;只有这个 USER Key 应写入 DeerFlow 的 OPENVIKING_API_KEY 变量。
身份与会话映射:线程 → Session → Peer
一个 DeerFlow 线程确定性地映射为一个 OpenViking Session
Session ID 由 session.py 中的 _session_id 派生:对 deerflow-openviking-adapter-v1 命名空间 + owner_user_id + peer_id + thread_id 做 SHA-256,取前 48 个十六进制字符,加 df_ 前缀。commit 在该 Session 内部创建 archive,而不创建新 Session——因此用户稍后回来时线程保持同一身份。
Peer:用户内部的作用域分离
- 默认 DeerFlow agent 使用
default_peer_id(默认deerflow); - 具名 agent 使用小写 OpenViking peer ID(agent 名 strip + lower);
- 不是合法 peer ID、与默认值冲突、或进入保留的
df-agent-命名空间的名字,会映射到抗碰撞 ID:_canonical_peer_id 对其 SHA-256 摘要取前 32 位拼上df-agent-前缀,保证与合法名互不别名; - USER Key 身份始终是安全边界;peer 只在该用户内部隔离记忆作用域。
检索时,_memory_target_uris 同时查询 viking://user/memories(用户全局)与 viking://user/peers/{peer_id}/memories(当前 peer)。在 get_context 中,如果请求带 thread_id,检索器切换为 search 模式并绑定该线程的 Session;否则为 find 模式做跨 Session 检索。
重试、游标与失败语义
读写失败策略的落点
read: fail_open:检索失败记日志并返回空字符串(无注入记忆);read: raise向 DeerFlow 调用方传播异常。对应 get_context / search 的异常分支:捕获异常后按策略raise或logger.warning降级。write: log_and_drop:捕获失败记日志,但不使已生成的回答失败;write: raise则抛出MemoryManagerError。见 _handle_write_error。- 启动期健康检查由
startup_policy控制:fail_fast下不健康直接抛错,warn下降级运行(warm)。
只存哈希的本地捕获游标
DeerFlow 只在 {storage_path}/openviking/sessions/ 下维护一个有界的本地捕获游标,其中只有哈希与计数器,从不存消息文本。游标的作用:
- 防止把完整的 LangGraph transcript 快照重复提交(每次捕获前用 _matching_prefix_count 比对已提交前缀,或基于
submitted_prefix_count+ 前缀摘要处理压缩后的情况); - 记录部分批次中已确认的进度,在追加更多消息前先重试失败的 commit(见下文);
- 不可读的游标按失败关闭处理:重放未知前缀可能复制私有对话历史,_load_cursor 对读不到/解析失败的游标直接抛
MemoryManagerError,拒绝不安全重放。
游标写入采用「临时文件 + os.replace」的原子替换(_save_cursor),避免半写状态。
消息签名的计算见 _message_signature:对 id / role / content / tool_calls / tool_call_id / tool_name / tool_status 做规范化 JSON 后 SHA-256,因此工具调用与结果的变化也会被感知。
部分写入与提交重试
捕获路径 _capture_locked 的流程:
- 若游标标记
commit_pending,先调用recorder.flush(session_id)重试上次未完成的提交;重试失败则按写策略处理并保留游标; - 计算已提交前缀,只提交增量
pending消息; - 捕获官方适配器抛出的
OpenVikingPartialWriteError:按input_messages_consumed把已确认前缀写入游标(commit_pending一并记录),下次捕获时先重试 commit; - 其他异常不推进游标;
- 全部成功后推进游标并清空
commit_pending。
整个写入在每 Session 一把 RLock(_session_lock)下串行,避免并发捕获互相覆盖游标。
优雅关闭
shutdown_flush(timeout)(openviking_manager.py#L288-L301):置关闭标志停止新工作,在 shutdown_flush_timeout_seconds 预算内等待已接受的操作排空,然后关闭 recorder 拥有的 SDK 客户端。它不引入新的 DeerFlow 生命周期或后台 worker,完全复用既有 memory 关闭契约。
明确的局限:不承诺 at-least-once
对于「丢失一次记忆更新不可接受」的部署,仍然需要引入持久化 outbox。该初始集成不声称 at-least-once 投递——write: log_and_drop 下的写入丢失是有意的可恢复性取舍,而非静默承诺。
适用前提与验证路径
- 仅支持
memory.mode: middleware;需要模型显式记忆工具时走 OpenViking MCP(独立集成面); - 需要
openviking-sdk>=0.1.6,<0.2(import 检查 在缺少 request-scoped actor-peer 支持时会明确报错); - 服务器必须处于
api_key模式,.env/ovcli.conf中不得残留 trusted 模式的身份字段; - 行为验证可参考仓库内测试:backend/tests/test_openviking_memory_backend.py 覆盖配置校验、游标与失败语义,backend/tests/test_openviking_mcp_integration.py 覆盖 MCP 集成面。
按上述步骤完成配置后,DeerFlow 会在每轮对话后把可捕获消息增量提交到该线程的 OpenViking Session,并在下一轮按固定查询把记忆注入系统提示;整个链路的身份隔离由 USER Key + owner_user_id 双重约束,任何跨用户访问都会在触达 OpenViking 之前被拒绝。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00