OpenViking Usage/Audit 模块实战指南为 Console 构建产品统计与请求审计的完整方案【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking导读Usage/Audit 是 OpenViking Server 提供给 Console产品控制台使用的产品统计与请求审计模块负责把模型调用、HTTP 请求等观测事件投影为上下文数据量、今日 Token、今日检索、上下文提交热力图、请求日志等产品语义数据。本文基于仓库中的官方说明文档openviking/observability/usage_audit/README.md与模块源码系统讲解其架构、配置项、数据口径、Console BFF API 与本地验证方法。读完本文你将能独立完成 Usage/Audit 的配置调优、数据口径核对、Console 接口对接与排障。一、模块定位产品语义数据而非运维指标Usage/Audit 解决的是一个边界问题Console 需要产品维度的统计与审计但不应为此引入 Prometheus 依赖也不应在正常 API 请求链路里同步写统计库。它复用了 OpenViking 已有的 observability 事件机制由独立的订阅者在后台把事件投影为统计与审计行。当前模块主要服务 Console P0 页面总览页首屏上下文数据量、今日 Token、今日检索、Agent 概览Token 趋势按日期范围查询模型 Token 消耗上下文提交热力图按日期和小时段查询上下文写入活动请求日志分页查询请求明细、状态、耗时和成功率。需要特别强调的是边界QPS、latency histogram、queue depth、cache hit/miss 等仍然是运维指标应该继续通过 Prometheus metrics 观测对应server.observability.metrics配置。Usage/Audit 只承载产品语义数据两者职责互补不互相替代。二、工作方式与数据流模块的整体数据流如下业务请求 / 模型调用 | v Observability Event Bus | -- Metrics subscriber | -- Usage/Audit subscriber | v Usage/Audit worker | v Usage/Audit store | v /api/v1/console/* BFF关键设计点均有源码佐证复用事件总线不打散打点Usage/Audit 通过register_event_subscriber(usage_audit, UsageAuditSubscriber(worker))订阅共享事件总线见 runtime.py不额外散落 Console 专用埋点。订阅者本身只是一个同步适配器把总线扇出转发到 worker 的异步队列见 subscriber.py。与 Metrics 解耦server.observability.metrics.enabledfalse不影响 Usage/Audit。两者的订阅关系在 runtime.py 中独立注册互不依赖。请求路径只做非阻塞投递worker 的enqueue()使用queue.put_nowait()同线程或call_soon_threadsafe()跨线程投递事件绝不阻塞调用方见 worker.py。bounded queue 丢弃计数队列满时统计事件会被丢弃同时累加dropped_count便于观察背压情况。关闭时兜底 flush服务关闭时close(timeout_seconds...)会尽量把队列中剩余事件刷完若已有 batch 正在写入会等待其完成避免尾部审计丢失或重复写入见 worker.py。从源码结构看worker 是典型的 批量攒批 定时 flush 模型每收到一个事件先入队后台循环要么攒满batch_size条、要么等待flush_interval_seconds超时就把一个 batch 一次性交给 store 落库见 worker.py。这解释了为什么 API 请求链路本身几乎无写入开销。三、配置详解Usage/Audit默认启用最小配置可以不写任何字段。完整配置示例JSON 结构对应 OpenViking Server 配置{ server: { observability: { usage_audit: { enabled: true, backend: sqlite, sqlite_path: /path/to/usage_audit.sqlite3, queue_size: 10000, batch_size: 500, flush_interval_seconds: 1.0, shutdown_flush_timeout_seconds: 3.0, usage_retention_days: 14, audit_retention_days: 7, audit_retention_per_account: 1000, timezone: local, inventory_ttl_seconds: 10.0 } } } }字段说明如下表默认值与 config.py 中的UsageAuditConfig定义一致字段默认值说明enabledtrue是否启用 Usage/Auditbackendsqlite当前仅支持 SQLitesqlite_pathnullSQLite 文件路径为空时使用当前 OpenViking workspace 下的_system/usage_audit/usage_audit.sqlite3queue_size10000后台写入队列大小配置模型要求0batch_size500单次批量写入的最大事件数要求0flush_interval_seconds1.0worker 定时 flush 间隔要求0shutdown_flush_timeout_seconds3.0服务关闭时 flush 等待时间要求0usage_retention_days14统计聚合数据保留天数包含 Token、检索、上下文写入热力图、Agent 活跃0表示不按天裁剪要求0audit_retention_days7请求审计日志保留天数0表示不按天裁剪audit_retention_per_account1000每个 account 保留的最新请求审计条数0表示不按条数裁剪timezonelocalConsole 请求未传timezone时的兜底查询时区写入始终按 UTC 保存。local表示 server 进程所在机器/容器的本地时区inventory_ttl_seconds10.0上下文当前数据量查询缓存时间要求0源码层面的几个要点配置模型禁止未知字段UsageAuditConfig设置了model_config {extra: forbid}写错字段名会直接报配置校验错误。SQLite 路径解析_resolve_sqlite_path()优先使用显式sqlite_pathexpanduserresolve否则读取 OpenViking 配置中的storage.workspace拼出_system/usage_audit/usage_audit.sqlite3默认路径workspace 不可用时兜底到DEFAULT_CONFIG_DIR见 runtime.py。worker 参数有下限保护queue_size、batch_size至少为 1flush_interval_seconds至少为 0.1 秒避免传入 0 或负值导致空转/忙循环见 worker.py。部署提示本地版使用 SQLite 没有问题。分布式生产环境如果多实例同时提供 Console建议后续增加共享 store backend而不是让多个实例各写各的本地 SQLite。当前实现下多实例各持局部统计无法形成全局一致的总览。四、数据口径每一类统计来自哪些事件4.1 Token来自模型调用事件事件投影逻辑见 projection.py事件当前 Console 展示口径vlm.callprompt_tokens计入vlm_inputcompletion_tokens计入vlm_outputembedding.callprompt_tokens计入embedding_inputrerank.call已可落库当前 Console summary/series 暂不展示投影时还会记录 provider 与 model_name 维度token 行按(account_id, user_id, date_utc, hour_utc, source, token_type, provider, model_name)聚合见 schema.py 中usage_token_hourly表定义为后续按模型、供应商拆分预留了能力。4.2 今日检索来自 HTTP 请求完成事件http.request路由映射见 projection.pyAPI routeoperationPOST /api/v1/search/findfindPOST /api/v1/search/searchsearch2xx和3xx记为success4xx/5xx记为error。Dashboard 今日检索只展示成功请求数——这在 SQLite 读路径中也有体现_fetch_hourly_retrieval_rows()的 SQL 明确带AND status success过滤见 sqlite_store.py。4.3 上下文提交热力图来自成功的公开写请求映射见 projection.pyAPI routeoperationPOST /api/v1/resourcesadd_resourcePOST /api/v1/skillsadd_skillPOST /api/v1/sessions/{session_id}/messagessession.add_messagePOST /api/v1/sessions/{session_id}/commitsession.commit只有2xx/3xx会进入上下文提交统计投影函数里显式判断200 status_code 400。4.4 上下文数据量库存Dashboard 首屏的上下文数据量是当前状态查询不是历史事件累加files读取viking://resources的stat.countskills读取当前 Agentskills根目录的stat.countmemories读取当前 User 和当前 Agent 的memories根目录stat.count后求和。stat.count是底层VikingFS.stat()暴露的目录计数字段。Usage/Audit 不自己拼 vector filter也不从历史写入事件累计当前库存——实现位于 inventory.py 的ContextInventoryProvider通过fs_service.stat(uri)并行读取三个目录并求和。该部分受inventory_ttl_seconds缓存保护默认 10 秒避免 Console 频繁刷新打到底层存储业务根目录不存在时按 0 处理避免新环境或空租户反复刷 warning_stat_count()捕获FileNotFoundError/AGFSNotFoundError/NotFoundError后返回 0。4.5 请求审计请求审计来自http.request事件保留字段如下见 projection.py 与request_audit表request_idaccount_iduser_idmethodrouteapi_typestatus_codeduration_mserror_code仅标准错误响应error_message仅标准错误响应error_details仅标准错误响应可空created_at错误字段来自 OpenViking 已返回给调用方的标准错误结构不读取或缓存 HTTP response body。error_details经过凭据脱敏和大小限制sanitize_public_http_error/serialize_public_error_details见 projection.py它可能包含被拒绝的参数值但不会额外保存原始 request body、header、query string、stack trace 或 exception text。以下 route不进入审计AUDIT_EXCLUDED_ROUTES集合 /api/v1/console/前缀排除见 projection.py/metrics/health/ready/docs/docs/oauth2-redirect/redoc/openapi.json/favicon.ico/favicon.png/apple-touch-icon.png/api/v1/console/*4.6 时区模型UTC 落库读端重分桶这是整个模块最值得注意的设计所有时间键列date_utc、hour_utc、created_at一律按 UTC 持久化查询端根据调用方传入的timezone动态重分桶见 sqlite_store.py 文件头注释与_user_day_window_utc()实现。Token 与检索按小时粒度聚合因此跨时区今日查询可以在用户本地日边界精确切片读路径先把用户本地日的[start, end)换算为 UTC 区间再做窗口化 SQL 查询并在 Python 中按用户时区重分桶。同一份存储可以同时服务任何地区的查看者。五、Console BFF API所有接口都挂在 OV Server 侧前缀统一为/api/v1/console/*Console 前端通过 Console server 的allowlist proxy访问代理路径形如/console/api/v1/ov/console/dashboard/summary /console/api/v1/ov/console/tokens /console/api/v1/ov/console/context-commits /console/api/v1/ov/console/audit权限要求ROOT和ADMIN可以访问普通USER返回403 PERMISSION_DENIED。注意ROOT/ADMIN 查询的是账号级聚合不按 user_id 过滤普通 USER 只能看到自己用户范围内的数据——这一逻辑体现在UsageAuditQueryService._usage_user_id()/_audit_user_id()见 api_service.py。5.1 Dashboard SummaryGET /api/v1/console/dashboard/summary参数参数必填说明timezone否IANA 时区名如Asia/Shanghai省略时回退到 server 时区用于确定今日的时区边界返回示例{ status: ok, result: { context_counts: { files: 12, skills: 3, memories: 8, total: 23 }, today_tokens: { vlm_input: 1000, vlm_output: 500, embedding_input: 200, total: 1700 }, today_retrievals: { find: 10, search: 4, total: 14 } } }如果 Usage/Audit 被关闭或尚未初始化返回{ status: ok, result: { enabled: false, message: Usage/Audit is disabled or not initialized. } }5.2 Token SeriesGET /api/v1/console/tokens?start_date2026-05-01end_date2026-05-12bucketday参数参数必填说明start_date是开始日期格式YYYY-MM-DD按timezone指定的时区解释end_date是结束日期格式YYYY-MM-DD按timezone指定的时区解释bucket否当前仅支持daytimezone否IANA 时区名如Asia/Shanghai省略时回退到 server 时区返回的date分桶按该时区返回中会补齐日期范围内没有数据的日期——读路径先为范围内每一天生成零值行再叠加实际数据见 sqlite_store.py保证前端画趋势图时不会出现空洞。5.3 Context CommitsGET /api/v1/console/context-commits?start_date2026-05-01end_date2026-05-12bucket4h参数参数必填说明start_date是开始日期格式YYYY-MM-DD按timezone指定的时区解释end_date是结束日期格式YYYY-MM-DD按timezone指定的时区解释bucket否hour或4h默认hourtimezone否IANA 时区名如Asia/Shanghai省略时回退到 server 时区返回的date/hour分桶按该时区返回中会补齐日期和小时段范围内没有数据的 bucket。4h分桶实现会把用户本地小时归一到(hour // 4) * 4的起点见 sqlite_store.py。5.4 Audit LogsGET /api/v1/console/audit?page1page_size20statussuccess,errorapi_typesearch.find参数参数必填说明page否页码从1开始page_size否每页条数范围1..100request_id否精确匹配 request idstatus否可重复传也可逗号分隔api_type否可重复传也可逗号分隔status支持以下取值过滤 SQL 生成逻辑见 sqlite_store.pysuccess/ok2xx和3xx2xx3xxerror/failed4xx/5xx4xx、5xx等通配段具体状态码例如404返回字段{ status: ok, result: { total: 123, success_rate: 0.98, page: 1, page_size: 20, items: [] } }success_rate使用当前筛选条件下的2xx/3xx占比status_code 200 AND status_code 400计数除以总数见 sqlite_store.py。error_details在返回时会被反序列化为 JSON 对象若无法解析则置为null。六、本地验证启动 server 后可以先通过一次检索请求触发数据curl -X POST http://127.0.0.1:1933/api/v1/search/find \ -H Authorization: Bearer $OPENVIKING_API_KEY \ -H X-OpenViking-Account: default \ -H X-OpenViking-User: default \ -H Content-Type: application/json \ -d {query:hello,limit:3}再查询 Console BFFcurl http://127.0.0.1:1933/api/v1/console/dashboard/summary \ -H Authorization: Bearer $OPENVIKING_API_KEY \ -H X-OpenViking-Account: default \ -H X-OpenViking-User: default如果使用 Console server则访问/console/api/v1/ov/console/*代理路径。注意模型调用类统计Token需要真实的 VLM / Embedding 调用才会产生vlm.call/embedding.call事件检索与审计统计由http.request驱动一次search/find请求即可验证。七、测试与代码质量仓库为 Usage/Audit 提供了覆盖各层级的单测可一键运行.venv/bin/python -m pytest \ tests/observability/test_events.py \ tests/observability/test_usage_audit_store.py \ tests/observability/test_usage_audit_worker.py \ tests/observability/test_console_router.py \ tests/observability/test_usage_audit_runtime.py \ tests/observability/test_usage_audit_inventory.py \ tests/misc/test_console_proxy.py其中 test_usage_audit_store.py 验证 SQLite 读写与保留策略test_usage_audit_worker.py 验证批量写入与关闭 flushtest_console_router.py 验证 BFF 接口与权限。另有 test_usage_audit_api_service.py 覆盖查询服务层test_usage_audit_runtime.py 覆盖运行时引导test_usage_audit_inventory.py 覆盖库存统计与缓存。相关 lint.venv/bin/python -m ruff check \ openviking/observability/events.py \ openviking/observability/usage_audit \ openviking/server/routers/console.py \ tests/observability八、常见问题8.1 Console 查询为什么返回enabledfalse通常是server.observability.usage_audit.enabledfalse或者 Usage/Audit runtime 没有初始化成功。先看 server 启动日志中是否有Usage/Audit store initialized with sqlite backend该日志在 runtime.py 中输出可作为初始化成功的标志。另外注意 Console 路由在 runtime 未挂载时统一返回_disabled_response()见 console.py。8.2 为什么 Dashboard 今天没有 Token确认模型调用事件是否触发VLM 需要产生vlm.callEmbedding 需要产生embedding.call统计数据写入时按 UTC 保存Console 查询会优先使用请求里的timezone参数做读端分桶。如果请求没有传timezone才会使用server.observability.usage_audit.timezone作为兜底。跨日边界场景最容易踩坑UTC 凌晨的 Token 在Asia/Shanghai视角下属于今天在 UTC 视角下可能属于昨天务必检查 timezone 是否一致。8.3 为什么请求日志里没有 Console 自己的请求这是预期行为。/api/v1/console/*和/console/*会被排除避免 Console 页面刷新污染产品请求审计。/health、/metrics、/docs等内部与文档路由同样被排除。8.4 为什么普通用户访问 Console BFF 是 403Console BFF 查询的是账号级聚合和审计明细当前只允许ROOT/ADMIN访问。普通USER会被require_role拦截并返回403 PERMISSION_DENIED。8.5 SQLite 文件在哪里如果没有配置sqlite_path默认在 OpenViking workspace 下workspace/_system/usage_audit/usage_audit.sqlite3可以通过server.observability.usage_audit.sqlite_path显式指定。数据库采用 WAL 模式PRAGMA journal_modeWAL并带 schema 版本管理_schema_meta表当前SCHEMA_VERSION 5见 schema.py不兼容的旧库会自动重建统计表。8.6 生产多实例怎么部署当前实现只有 SQLite backend更适合单机本地版。多实例生产环境需要共享 store backend避免每个实例只持有自己的局部统计。后续扩展时应实现UsageAuditStore协议见 store.py 中的 Protocol 定义而不是改 Console BFF——接口稳定、后端可替换是这套架构留出的扩展位。九、小结Usage/Audit 用一套事件总线订阅 后台批量投影 SQLite 落库 BFF 只读查询的架构为 Console 提供了低成本、与 Prometheus 解耦的产品统计与审计能力。理解其数据口径哪些事件进哪些统计、时区模型UTC 落库、读端重分桶与保留策略按天/按条数裁剪是正确使用与二次开发的前提。若后续需要共享存储从UsageAuditStore协议扩展即可无需改动 Console BFF 接口契约。【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
