WeKnora Go SDK 怎么在 Go 应用中完成认证并调用知识库与流式问答接口
【免费下载链接】WeKnoraOpen-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.项目地址: https://gitcode.com/GitHub_Trending/we/WeKnora
如果你的 Go 服务要接入 WeKnora 的知识平台——先完成认证,再调用知识库接口并发起流式(SSE)问答——这篇文章给出一条用官方 Go SDK 完成的连续操作路径。SDK 源码位于仓库client/目录,以独立 Go module 发布,官方 CLI 和服务端内部调用也复用这个 SDK;你需要一个运行中的 WeKnora 服务和一种可用凭证。
准备条件
Go module 在 client/go.mod 中声明go 1.24.2,本地 Go 工具链需要不低于该版本。
服务地址方面,官方文档的示例统一使用http://localhost:8080,部署到其他环境时替换为实际地址。凭证有两种:
- API Key(长期):以
X-API-Key请求头发送; - 账号邮箱 + 密码:先登录换取短期 JWT,再以
Authorization: Bearer <token>请求头发送。
安装 SDK:
go get github.com/Tencent/WeKnora/client导入:
import "github.com/Tencent/WeKnora/client"创建客户端:API Key 与 JWT 两种认证
客户端由NewClient(baseURL string, options ...ClientOption)构造。默认普通请求超时 30 秒;流式(SSE)请求默认无超时,生命周期由传入的context控制,除非显式调用WithTimeout(会同时给普通请求和流式请求设置上限)。
路径一:API Key
ctx := context.Background() apiClient := client.NewClient( "http://localhost:8080", // 替换为实际 WeKnora 服务地址 client.WithAPIKey("your-api-key"), // 替换为你的 API Key )WithAPIKey设置凭证后,每个请求都会自动附加X-API-Key头,注入逻辑见 client/client.go 的applyAuthHeaders。
路径二:邮箱密码登录换取 JWT
Login(client/auth.go)对应POST /api/v1/auth/login,返回 JWT access token、refresh token 和主体信息:
c := client.NewClient("http://localhost:8080") loginResp, err := c.Login(ctx, client.LoginRequest{ Email: "user@example.com", // 替换为账号邮箱 Password: "your-password", // 替换为账号密码 }) if err != nil { return err } // 用返回的 access token 重建带认证的客户端 authed := client.NewClient("http://localhost:8080", client.WithBearerToken(loginResp.Token))这里注意:LoginResponse中 access token 的字段名是Token(SDK 文档示例里写作AccessToken,但实际结构体中该字段名是Token,以 client/auth.go 为准)。
token 过期时用RefreshToken(ctx, refreshToken)换新 token 对(RefreshTokenResponse.AccessToken/.RefreshToken);用GetCurrentUser(ctx)(对应GET /api/v1/auth/me)可以验证 bearer 是否有效,并拿到当前用户与租户信息。
凭证并存与租户头的边界
- 两种凭证可同时配置,但 HTTP 层
X-API-Key优先; WithTenantID会在每个请求上附加X-Tenant-ID,仅用于具备CanAccessAllTenants权限的跨租户显式访问。JWT 与租户级 API Key 本身已携带租户身份,普通用户不应设置该头——服务端 auth 中间件会对携带该头的 bearer 请求执行跨租户校验,普通用户会得到 403;WithToken是WithAPIKey的 v0.x 兼容别名,将在下个大版本移除,新代码应使用WithAPIKey。
调用知识库接口
知识库接口在 client/knowledgebase.go。下面这段取自官方文档示例(改编自 client/example.go 中的真实代码),创建一个带分块配置的知识库:
ctx := context.Background() kb := &client.KnowledgeBase{ Name: "Test Knowledge Base", Description: "This is a test knowledge base", ChunkingConfig: client.ChunkingConfig{ ChunkSize: 500, ChunkOverlap: 50, Separators: []string{"\n\n", "\n", ". ", "? ", "! "}, }, EmbeddingModelID: "embedding_model_id", // 文档占位值,替换为服务端实际 Embedding 模型 ID SummaryModelID: "summary_model_id", // 文档占位值,替换为实际摘要模型 ID } createdKB, err := apiClient.CreateKnowledgeBase(ctx, kb) if err != nil { // 处理错误 } fmt.Printf("Knowledge base created: ID=%s, Name=%s\n", createdKB.ID, createdKB.Name)embedding_model_id和summary_model_id是文档示例中的占位值,必须替换为服务端实际配置的模型 ID;可用ListModels(ctx)拉取模型列表核对。CreateKnowledgeBase会在服务端创建真实资源,验证完可用DeleteKnowledgeBase(ctx, createdKB.ID)清理。如果需要把文档灌入知识库,用CreateKnowledgeFromFile(ctx, kbID, filePath, metadata, nil, "", "", nil)上传本地文件(见 client/knowledge.go)。
创建会话并进行流式问答
流式问答在 client/session.go。先用CreateSession建会话,再用KnowledgeQAStream发起 SSE 流(以下代码为节选,实际程序需自行导入context、fmt、strings等包):
// 1. 创建会话 session, err := apiClient.CreateSession(ctx, &client.CreateSessionRequest{ Title: "Test Session", Description: "A test session for knowledge Q&A", }) if err != nil { return err } // 2. 流式问答:累积答案与引用 question := "What is artificial intelligence?" var answer strings.Builder var references []*client.SearchResult err = apiClient.KnowledgeQAStream(ctx, session.ID, &client.KnowledgeQARequest{Query: question}, func(response *client.StreamResponse) error { if response.ResponseType == client.ResponseTypeAnswer { answer.WriteString(response.Content) } if response.Done && len(response.KnowledgeReferences) > 0 { references = response.KnowledgeReferences } return nil }) if err != nil { return err } fmt.Printf("Answer: %s\n", answer.String()) for i, ref := range references { fmt.Printf("Reference %d: %s\n", i+1, ref.Content) }流式机制的几个关键点:
KnowledgeQAStream内部用bufio.Scanner逐行解析 SSE(event:/data:前缀,空行分帧),每解析出一帧调用一次回调;回调返回非 nil error 会立即中止流;- 每帧
StreamResponse携带ResponseType(answer、references、thinking、tool_call、tool_result、error、reflection、session_title、complete等)、增量Content、结束标记Done,以及Done帧上的KnowledgeReferences(引用来源); - 该方法实际请求
POST /api/v1/knowledge-chat/{sessionID};KnowledgeQARequest的KnowledgeBaseIDs字段可以把这次问答限定到指定知识库; - 接口签名末尾有变参
opts ...ResourceURLOptions,传入后可在流中拿到引用文件的公开 HTTP(S) 直链,不需要时忽略。
结果验证与错误处理
成功判断方式(与文档示例一致):KnowledgeQAStream返回 nil 错误;回调中累积的answer非空;若服务端给出引用,Done帧上的KnowledgeReferences非空,可逐条打印ref.Content。
SDK 分两层错误,处理方式不同:
HTTP 层APIError(client/client.go):所有非 2xx 响应封装为*APIError,用errors.As按状态码或服务端结构化错误码分支:
var apiErr *client.APIError if errors.As(err, &apiErr) { switch { case apiErr.StatusCode == 404: // 资源不存在 case apiErr.Code == client.ServerErrUnauthorized: // 1001 // token 失效,触发重新登录或刷新 } }Code取自响应体{"code":N},包内常量从ServerErrBadRequest(1000) 到ServerErrValidation(1010)。
流层SSEStreamError(client/stream_errors.go):当服务端在流上发出终止错误帧(response_type=error, done=true)时,SDK 会先把该帧交给回调,然后返回*SSEStreamError。判断方式(两者等价,推荐前者):
if errors.Is(err, client.ErrSSEStreamTerminal) { fmt.Printf("Stream terminated by server error: %v\n", err) } // 等价写法: if client.IsSSEStreamError(err) { ... }可选:调试日志与链路追踪
需要观察 SSE 逐行解析过程或请求失败原因时,在程序启动时调用一次(输出到 stderr):
client.SetDebugLevel("debug") // "debug"/"info"/"warn";其他值(含 "error"、"")静默该函数非并发安全,必须在任何 SDK 调用发起前调用一次。链路追踪方面,在 context 中放入"RequestID"(string),SDK 会自动作为X-Request-ID请求头发送:
ctx = context.WithValue(ctx, "RequestID", "req-20260727-0001")限制
- 流式请求默认无超时,长问答要靠
ctx(如context.WithTimeout)控制生命周期;需要统一上限时显式调用WithTimeout,它同时作用于普通请求与流式请求; WithTenantID/X-Tenant-ID仅限CanAccessAllTenants主体做跨租户访问,普通用户设置会被 403 拒绝;WithAPIKey与WithBearerToken同时配置时,实际生效的是X-API-Key,JWT 不会被使用。
完整方法清单与更多示例见 website-docs/05-clients/03-go-sdk.md,可运行示例见 client/example.go。
【免费下载链接】WeKnoraOpen-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.项目地址: https://gitcode.com/GitHub_Trending/we/WeKnora
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考