OpenViking Go SDK 实战指南:用 Go 语言操作自进化上下文数据库的完整方案
本指南以 sdk/go/README.md 为核心,系统讲解 OpenViking Go SDK 的安装、客户端配置、身份认证、资源/技能/会话/记忆等核心 API 的用法,并深入其源码实现(客户端初始化、HTTP 传输封装、目录打包上传、图像输入归一化等)。读完本文,你将掌握如何在一个运行中的 OpenViking 服务器之上,用 Go 语言完成资源导入、语义检索、技能管理、会话记忆提交与 Peer 级记忆隔离等全套 Agent 上下文工程操作。
一、SDK 定位:一个 HTTP 客户端,而非独立服务
OpenViking 是一个面向 AI Agent 的"自进化上下文数据库"(Self-evolving Context Database),统一了 Agent 记忆(Memory)、知识检索(Knowledge RAG)与技能(Skills)。Go SDK 不是服务端组件,而是运行中 OpenViking 服务器的 HTTP 客户端,它作为独立 Go module 内嵌于主仓库中(见 sdk/go/go.mod,module github.com/volcengine/OpenViking/sdk/go,要求 Go 1.22+)。
从 client.go 可以看到,Client 结构体只持有 baseURL、httpClient、身份字段(apiKey、account、user、actorPeerID)以及 profile、uploadMode 等轻量状态——所有真实逻辑都在服务端,SDK 只负责把请求编码为 OpenViking 的 HTTP 协议并解析统一响应信封。
安装方式(在当前仓库的 sdk/go 目录下运行测试,或在你自己的 Go 工程中引入):
go get github.com/volcengine/OpenViking/sdk/go
二、客户端初始化:Config 配置项与默认值
2.1 最小可用示例
package main
import (
"context"
"fmt"
"log"
"time"
openviking "github.com/volcengine/OpenViking/sdk/go"
)
func main() {
ctx := context.Background()
client, err := openviking.NewClient(openviking.Config{
BaseURL: "http://localhost:1933",
APIKey: "your-key",
Timeout: 120 * time.Second,
})
if err != nil {
log.Fatal(err)
}
defer client.CloseIdleConnections()
ok, err := client.Health(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("healthy:", ok)
}
2.2 Config 完整字段与源码语义
Config 定义在 types.go,结合 client.go 的初始化逻辑,各字段语义如下:
| 字段 | 类型 | 说明 |
|---|---|---|
BaseURL |
string |
必填。SDK 会 TrimRight 末尾 / 并校验 URL 的 scheme 与 host,非法 URL 直接返回错误 |
APIKey |
string |
API 密钥,映射为 X-API-Key 请求头 |
Account |
string |
账号标识,映射为 X-OpenViking-Account |
User |
string |
用户标识,映射为 X-OpenViking-User |
ActorPeerID |
string |
Actor(Agent)Peer 标识,映射为 X-OpenViking-Actor-Peer,是"新 SDK 身份体系"的核心 |
Timeout |
time.Duration |
HTTP 客户端超时,为 0 时默认 60 秒(client.go) |
HTTPClient |
*http.Client |
自定义 HTTP 客户端,传入后 SDK 不再自行构造(可用它注入传输层中间件) |
ExtraHeaders |
map[string]string |
追加任意自定义请求头 |
Profile |
bool |
为 true 时每次请求自动追加 profile=1 查询参数,开启服务端性能剖析输出 |
UploadMode |
string |
上传临时文件时作为 upload_mode 表单字段传给服务端 |
2.3 统一响应信封与请求管线
所有 JSON 请求都经过 transport.go 的 newRequest 与 doJSON:
- 请求路径自动补
/前缀,query 参数合并; - 身份头按非空原则逐一注入(见下节);
- 服务端响应统一为
{status, result, error, telemetry, profile}信封(responseEnvelope),doJSON会解包result反序列化到目标结构,error非空时转为*openviking.Error; - 响应体为空或
result为null时返回nil,不触发反序列化。
三、身份头与多租户模型:APIKey 够用,Account/User 慎用
Go SDK 发送与 Python HTTP 客户端完全一致的身份头(映射实现在 transport.go):
| Config 字段 | HTTP 请求头 |
|---|---|
APIKey |
X-API-Key |
Account |
X-OpenViking-Account |
User |
X-OpenViking-User |
ActorPeerID |
X-OpenViking-Actor-Peer |
部署模式决定了你要填哪些字段:
- 常见的
api_key部署模式:只填APIKey即可,服务器会根据密钥推导出 account 与 user 身份; - 可信部署或网关透传场景:仅当上游显式通过 OpenViking 头转发租户身份时,才设置
Account和User; - SDK 不实现旧的
agent_id兼容逻辑(README 明确说明),Peer 隔离一律通过ActorPeerID表达。这也是examples/basic_usage/main.go中"创建第二个仅带ActorPeerID的客户端来检索 Peer 级记忆"(见 main.go)能够生效的原因。
四、核心操作实战:资源、内容、检索、会话
README 的"Common Operations"一节演示了最常用的四类操作,这里逐段展开并补充参数细节:
// 1. 添加本地文件或远程 URL。本地文件/目录会先上传。
resource, err := client.AddResource(ctx, "./docs/readme.md", &openviking.AddResourceOptions{
To: "viking://resources/docs",
Wait: true,
})
// 2. 读取与更新内容。
content, err := client.Read(ctx, "viking://resources/docs/readme.md", 0, -1)
updated, err := client.Write(ctx, "viking://resources/docs/readme.md", content+"\n\nUpdated.", &openviking.WriteOptions{
Mode: "replace",
Wait: true,
})
// 3. 语义检索相关上下文。
results, err := client.Find(ctx, "how do I configure auth?", &openviking.FindOptions{
TargetURI: "viking://resources/docs",
Limit: 10,
ContextType: []string{"resource"},
})
for _, item := range results.Resources {
fmt.Println(item.URI, item.Score)
}
// 4. 按图像检索。Image 接受本地路径、viking:// URI、HTTP URL 或 data:image URI。
imageResults, err := client.Find(ctx, "", &openviking.FindOptions{
TargetURI: "viking://resources/images",
Image: "./query.png",
Limit: 5,
})
similarPosters, err := client.Search(ctx, "similar poster", &openviking.SearchOptions{
TargetURI: "viking://resources/images",
Image: "viking://resources/images/poster.png",
Limit: 5,
})
4.1 AddResource 的路径类型判断
AddResource(resources.go)把第一个参数 path 交给 addLocalUpload 分流处理:
- 以
http://、https://、git@、ssh://、git://开头 → 视为远程地址,直接以path字段提交; - 本地普通文件 → 先走
/api/v1/resources/temp_upload上传,请求体携带temp_file_id与source_name; - 本地目录 → SDK 先打包为 zip(见下文),再走临时上传;
- 路径不存在 → 原样透传
path交给服务端判断。
注意 To 与 Parent 互斥,同时指定会返回错误;Args 仅在非空时才序列化进请求体(resources.go),这是为了避免向较早版本服务端发送空 args 对象触发 body.args: Extra inputs are not permitted 校验错误,行为与 Python SDK 的 _compact_request_body、Rust CLI 的 compact_request_body 对齐。
4.2 Find 与 Search 的结构化结果
Find/Search 都返回 *FindResult(types.go),内部按 Memories、Resources、Skills 三类命中分区,并可选附带 QueryPlan(查询改写/多路召回的计划)与 Total。单个命中为 MatchedContext,暴露 URI、ContextType、Level、Abstract、Content、Overview、Score、MatchReason、Tags 等字段,其中 tags 与服务端 search_tags 对齐,便于与 Find/Search 的 Tags 过滤参数配合使用。
4.3 图像输入归一化
Image 字段支持本地路径、viking:// URI、HTTP(S) URL、data:image/... URI 四种形式,判断逻辑在 normalizeImageInput:只有本地文件会被读取并 base64 编码为 data:<mime>;base64,...(MIME 按扩展名推断,非 image/* 或未知时回退为 image/png),其他形式原样透传。路径存在与否是分流依据:本地不存在的路径不会被误读为文件。
4.4 会话、消息与记忆提交
session, err := client.CreateSession(ctx, &openviking.CreateSessionOptions{
SessionID: "demo-session",
MemoryExtractionConfig: map[string]any{
"events": map[string]any{
"tags": []string{"team=search", "channel=web"},
},
},
})
_, err = client.CreateSession(ctx, &openviking.CreateSessionOptions{
SessionID: "manual-session",
DisableAutoCommit: true,
})
_, err = client.UpdateSessionConfig(ctx, "demo-session", &openviking.UpdateSessionConfigOptions{
AutoCommitPolicy: openviking.Map(map[string]any{"message_count_threshold": 25}),
MemoryExtractionConfig: map[string]any{
"events": map[string]any{"tags": []string{"team=search", "channel=app"}},
},
})
_, err = client.UpdateSessionConfig(ctx, "demo-session", &openviking.UpdateSessionConfigOptions{
AutoCommitPolicy: openviking.Map(nil), // 显式 JSON null 关闭自动提交
})
_, err = client.AddMessage(ctx, "demo-session", openviking.Message{
Role: "user",
Content: openviking.String("remember this deployment decision"),
})
commit, err := client.CommitSession(ctx, "demo-session", &openviking.CommitSessionOptions{
KeepRecentCount: openviking.Int(2),
EventTags: []string{"team=search", "channel=web"},
})
会话 API 的底层行为可从 sessions.go 确认:
CreateSession(L12-L32)在DisableAutoCommit为 true 时把auto_commit_policy显式置为 JSONnull,而不是省略字段;UpdateSessionConfig(L53-L69)走PATCH /api/v1/sessions/{id}/config,AutoCommitPolicy为指针类型,传openviking.Map(nil)才能表达"显式关闭",传 nil 则省略字段——这是指针参数(helpers.go 中的String/Bool/Int/Float64/Map辅助函数)存在的意义:区分"省略"与"零值/空值";CommitSession(L148-L172)在设置EventTags时,会将其封装进extraction_metadata.event.tags结构,作为记忆抽取的事件标签元数据;GetSessionContext(L84-L93)的token_budget传 0 时默认使用 128000 token 预算;GetTask(L175-L189)在任务不存在时返回(nil, nil)而非报错,方便轮询代码直接判空;- 额外的
CancelTask、BatchAddMessages(一次请求批量追加多条Message,消息体支持Parts多模态结构)也是会话能力的一部分。
五、API 覆盖矩阵:已实现与刻意未实现
Go SDK v1 有意与 Python HTTP 客户端的能力面保持一致。README 给出了完整矩阵:
已实现
| 领域 | Go 方法 |
|---|---|
| 资源与技能导入 | AddResource、AddSkill、WaitProcessed |
| 技能管理 | ListSkills、FindSkills、ValidateSkill、GetSkill、UpdateSkill、DeleteSkill |
| Watch 管理 | ListWatches、GetWatch、UpdateWatch、DeleteWatch、TriggerWatch |
| 文件系统与内容 | List、Tree、Stat、Attrs、Mkdir、Remove、Move、Read、Abstract、Overview、Write、SetTags、Reindex |
| 检索 | Find、Search、Grep、Glob |
| 会话与任务 | CreateSession、ListSessions、GetSession、UpdateSessionConfig、SessionExists、GetSessionContext、GetSessionArchive、DeleteSession、AddMessage、BatchAddMessages、CommitSession、GetTask、ListTasks |
| Packs | ExportOVPack、BackupOVPack、ImportOVPack、RestoreOVPack |
| 系统与观测 | Health、CheckConsistency、GetStatus、IsHealthy、QueueStatus、VikingDBStatus、ModelsStatus |
| 管理端 | AdminCreateAccount、AdminCreateAccountWithOptions、AdminListAccounts、AdminDeleteAccount、AdminRegisterUser、AdminRegisterUserWithOptions、AdminListUsers、AdminRemoveUser、AdminSetRole、AdminRegenerateKey、AdminRegenerateKeyWithOptions、AdminMigrate |
未实现(刻意排除)
| 领域 | 原因 |
|---|---|
旧 agent_id 兼容 |
新 SDK 只使用 ActorPeerID |
| Privacy 配置路由 | 目前仅服务端管理面,Python HTTP 客户端也没有 |
| Metrics 端点 | Prometheus 文本抓取端点,不属于 JSON SDK API |
| Console/debug/backend-sync/session tool-result 端点 | 运维或服务端专用端点,超出 Python HTTP 客户端对等范围 |
5.1 README 未列出的额外能力
源码中还存在少量超出上表的方法,可作为补充:
- 上下文组装:
SearchContext(retrieval.go)执行服务端上下文组装,返回 SearchContextResult(Entries/Rendered/Digest/Stats),SearchContextOptions(types.go)支持MaxTokens、Quotas、Purpose、ExcludeURIs、PeerScope、OtherPeerPenalty、Rewrite等组装级参数; - 编译:
Compile(compile.go); - ACL:
ACL/SetACL/SetACLMode/GrantACL/RevokeACL/DeleteACL(acl.go); - Agent 进化观测:
ListExperienceTrajectories、GetExperienceOutcomes(agent_evolution.go); - OpenViking Assets:
ResolveOpenVikingAssets、PreflightOpenVikingAsset(openviking_assets.go),后者支持AssetGitAuth一次性 Git 认证做访问预检; - 组管理:
AdminCreateGroup、AdminListGroups、AdminDeleteGroup、AdminListGroupMembers、AdminAddGroupMember、AdminRemoveGroupMember(admin.go); - Agent Evolution 全局开关:
AdminGetAgentEvolution、AdminSetAgentEvolution、AdminGetAccountSettings、AdminSetAccountAgentEvolution(admin.go)。
六、管理端用户配置:Seed 派生密钥的确定性
当需要为新用户附带服务端初始配置时,使用 options 变体方法。普通 add 调用不需要显式设置 SDK 默认值——省略 To/TargetURI,让服务端解析用户与部署默认值即可。
seed := "alice-seed"
_, err := client.AdminRegisterUserWithOptions(ctx, "acme", "alice", "user", &openviking.AdminRegisterUserOptions{
Seed: &seed,
UserConfig: map[string]any{
"add_targets": map[string]any{
"resource_uri": "viking://~/resources/project-a",
"skill_uri": "viking://~/skills",
},
},
})
newSeed := "alice-new-seed"
_, err = client.AdminRegenerateKeyWithOptions(ctx, "acme", "alice", &openviking.AdminRegenerateKeyOptions{
Seed: &newSeed,
})
关键语义(README 明确给出):
- 设置
Seed时,返回的 API 密钥由sha256(user_id + "\0" + seed)确定性派生,适合需要可复现密钥的自动化场景; - 省略
Seed则随机生成密钥; - 传
nil表示省略Seed;传字符串指针(包括空字符串)则显式发送,空字符串会被服务端拒绝。
配合 AdminRegenerateKey(无 options 版本)可随时轮换用户密钥;AdminListAccounts/AdminListUsers 的 options 版本还支持通配符(*、?)名称匹配与可选分页(Limit 生效时 Page 才生效,且 Page 从 1 开始)。
七、文件、目录与 Packs:打包上传的底层机制
AddResource 和 AddSkill 都接受本地文件与目录。目录的处理流程(upload.go 的 zipDirectory + addLocalUpload):
- SDK 将目录递归打包为临时 zip(
openviking-upload-*.zip); - 符号链接被跳过(目录型 symlink 直接
SkipDir,文件型跳过,非普通文件一律不打包); - 通过 multipart 表单上传到
/api/v1/resources/temp_upload,携带temp_file_id; - 最终 API 调用使用
temp_file_id而非原始路径; - 上传完成后临时 zip 立即删除。
_, err := client.AddSkill(ctx, "./skills/search-web", &openviking.AddSkillOptions{
Wait: true,
})
skills, err := client.ListSkills(ctx, nil)
found, err := client.FindSkills(ctx, "search the web", &openviking.FindSkillsOptions{
Limit: 5,
})
_, _ = skills, found
exported, err := client.ExportOVPack(ctx, "viking://resources/docs", "./backups", nil)
restored, err := client.RestoreOVPack(ctx, exported, &openviking.ImportPackOptions{
OnConflict: "overwrite",
})
_, _ = exported, restored
Packs 方向:ExportOVPack 把指定 URI 导出为 ovpack 文件(PackOptions.IncludeVectors 控制是否携带向量),BackupOVPack 做整库备份,ImportOVPack/RestoreOVPack 分别支持指定父目录导入与整库恢复,ImportPackOptions.OnConflict(如 overwrite)与 VectorMode 控制冲突与向量处理策略。
八、Watch 管理:让资源持续跟随外部变化
AddResource 在 WatchInterval 大于 0 时会顺带创建 Watch 任务,之后可用专门的 Watch 方法管理既有任务:
watches, err := client.ListWatches(ctx, &openviking.ListWatchesOptions{
ActiveOnly: true,
})
updated, err := client.UpdateWatch(ctx, openviking.UpdateWatchOptions{
ToURI: "viking://resources/docs",
WatchInterval: openviking.Float64(30),
IsActive: openviking.Bool(true),
})
triggered, err := client.TriggerWatch(ctx, openviking.WatchRef{
ToURI: "viking://resources/docs",
})
_, _, _ = watches, updated, triggered
- Watch 任务可通过
WatchRef{TaskID}或WatchRef{ToURI}二选一标识(watches.go); UpdateWatchOptions支持调整WatchInterval(秒)、IsActive开关,以及Reason/Instruction说明字段;TriggerWatch可手动触发一次立即检查,适合在改完源之后立刻同步。
九、错误处理:结构化 API 错误与错误码判定
OpenViking API 错误统一返回 *openviking.Error,其结构(errors.go)为 Code、Message、Details(map[string]any)、StatusCode:
_, err := client.Read(ctx, "viking://resources/missing.md", 0, -1)
if openviking.IsCode(err, "NOT_FOUND") {
fmt.Println("missing resource")
}
var apiErr *openviking.Error
if errors.As(err, &apiErr) {
fmt.Println(apiErr.Code, apiErr.StatusCode, apiErr.Details)
}
IsCode(errors.go)用errors.As判定错误码,可穿透包装错误;- 响应信封中
status == "error"但缺少error对象时,SDK 会兜底构造Code: "UNKNOWN"(transport.go); - HTTP 状态码非 2xx 且无结构化错误时,同样返回
UNKNOWN码并尽量从detail字段提取可读信息(transport.go); - 这是
SessionExists(sessions.go)与GetTask把NOT_FOUND当作"不存在"处理的基础——错误码约定贯穿 SDK 内部逻辑。
十、测试与 Smoke Test:验证 SDK 的两种姿势
10.1 单元测试
cd sdk/go
go test ./...
仓库自带 1957 行的 client_test.go,覆盖配置校验、URI 归一化、请求构造、错误解码、图像归一化等行为,是了解各方法边界条件的活文档。
10.2 对真实服务器的冒烟测试
编辑 examples/basic_usage/main.go 顶部的常量(默认 baseURL = "http://localhost:1940",apiKey 留空表示服务器无需认证),然后运行:
cd sdk/go
go run ./examples/basic_usage
该脚本的完整执行流(README 概述 + 源码确认):
- 健康检查:
Health; - 导入资源:创建临时 Markdown 文件 →
AddResource导入为 OpenViking 资源 →WaitProcessed等待后台处理完成; - 列出与读取:
List(递归、simple)验证目录结构,Read读取内容; - 写入与检索:
Write(replace 模式)更新内容 →Find做语义检索并打印命中 URI 与分数; - Watch 管理:以
WatchInterval: 60创建资源 →ListWatches→UpdateWatch暂停/恢复 →TriggerWatch手动触发,结束前DeleteWatch清理; - 技能管理:
ValidateSkill(strict)→AddSkill→ListSkills/GetSkill→UpdateSkill(附带SourceMetadata)→FindSkills,结束前DeleteSkill清理; - 会话提交:
CreateSession→BatchAddMessages批量写入 6 条含 user/assistant 与 PeerID 的消息 →GetSessionContext读取组装上下文 →CommitSession(KeepRecentCount: 0)→ 轮询GetTask等待记忆抽取任务完成(最多 3 分钟,见waitForTask),并用ListTasks复查session_commit任务; - 记忆检索与 Peer 隔离:用默认客户端
Find检索用户级记忆 marker;再新建一个仅携带ActorPeerID的客户端(main.go),检索 Peer 级记忆 marker,验证记忆按 Peer 隔离。
每一步输出都以 1.、2.… 编号打印,缺依赖或行为变化时脚本会以 log.Fatal 直接失败——这是最直观的"SDK + 服务端契约一致性"验收手段。
十一、与其他 SDK 的一致性说明
Go SDK 的 URI 约定(viking:// 前缀归一化,见 NormalizeURI)、身份头体系、响应信封与 Python 版 HTTP 客户端保持同一契约,且均不含旧 agent_id 兼容层。如果你同时维护多语言 Agent 基础设施,可以放心地把身份、检索、会话这三个维度的调用逻辑按相同语义在不同语言间平移。服务端路由(如 /api/v1/resources、/api/v1/fs/*、/api/v1/content/*、/api/v1/sessions/*、/api/v1/tasks)对应实现位于 openviking/server/routers 目录,需要深挖协议细节时可对照查阅。
结语
OpenViking Go SDK 以极轻的 HTTP 客户端形态,覆盖了资源导入、语义/图像检索、技能生命周期、会话记忆提交、Watch 同步、ovpack 备份恢复与管理端用户配置等 Agent 上下文工程的完整操作面。配合仓库内的单元测试与端到端冒烟示例,你可以在数分钟内完成从"连接服务器"到"提交一段会演化为长期记忆的会话"的完整闭环,并将 Peer 级身份隔离贯穿始终。
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 StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00