Ngôn ngữ: English · Tiếng Việt · 中文
Business rules, deployment procedures, test matrix, troubleshooting playbook. Đây là thứ bạn đọc trước khi roll Viking ra team.
Quyết định: OpenViking chạy self-hosted, một instance mỗi team (hoặc mỗi individual cho solo devs). Không phải SaaS model.
Lý do:
- Default port
127.0.0.1:1933và single-server architecture của OpenViking signal "local-first" - Triết lý privacy-first của OpenSpace (self-evolution, local skill DB) match với điều này
- Team LAN deployment rẻ (single docker container)
- Không data egress nghĩa là tuân thủ quy định dễ dàng
Deployment shapes:
- Solo dev:
docker run -p 1933:1933 volcengine/openviking:latesttrên laptop - Small team: single shared Viking instance trên team LAN hoặc internal cloud
- Enterprise: nhiều Viking instances partition theo team hoặc data classification
Quyết định:
- Agent memories (
tools,patterns,skills,cases) → team-shared - User memories (
preferences,profile) → per-user isolated
Lý do: Tool knowledge là toàn bộ điểm của collective intelligence — duplicate "chromedriver version compatibility" per user phá bỏ mục đích. User preferences, ngược lại, là cá nhân: "Alice prefers bar charts" không bao giờ được surface trong sessions của Bob.
Enforcement: URI prefix segregation qua namespace + user_id config. agent_memory_uri() của client return team-scoped paths; user_memory_uri() return user-scoped paths. Directory filter target_uri của Viking enforce boundary phía server.
Threat model coverage:
- Honest user trên shared Viking: isolation ngăn preference leakage vô tình
- Honest team member trên namespace sai: namespace misconfiguration lands trong wrong memory bucket nhưng không exfiltrate data
- Malicious user: out of scope — yêu cầu Viking-level RBAC (API key scoping)
Quyết định:
- Raw session data → 30-day TTL (configure phía Viking)
- Extracted memories → permanent (sống sót khỏi session deletion)
Lý do:
- Sessions là audit trail — lớn, duplicate với memories sau extraction
- Memories đã dedup và curated — store permanent
- Ở 100 users × 10 tasks/day × 3 evolved skills = 3,000 sessions/day ≈ 90k/month × ~5KB = ~450MB/month raw session data
- 30 days cho forensic window đủ cho debugging mà không storage chạy tung
Implementation: Viking-side config (sessions.retention_days). OpenSpace không manage retention; nó chỉ tạo sessions và để Viking age chúng out.
Quyết định: Team sở hữu pushed skill resources; tác giả được credit trong metadata.
Lý do: Collective intelligence nghĩa là team tổng thể hưởng lợi từ evolved skill của bất kỳ member nào. Individual ownership xung đột với toàn bộ điểm của cross-agent sharing. Attribution giữ lại câu chuyện "ai đóng góp gì" mà không gate access.
Implementation: push_evolved_skills() đính kèm metadata:
{
"source": "openspace",
"origin": "derived" | "captured" | "fixed",
"description": "<skill description>",
"parent_skill_ids": ["parent1", "parent2"],
"change_summary": "what changed vs parent",
"generation": <int>
}Team admins manage deletion qua resource management của chính Viking (out of OpenSpace scope).
Quyết định: Static env var, rotate qua restart. Không hot reload.
Lý do:
- OpenSpace processes thường short-lived (CLI one-shots, MCP servers)
- Rotation qua restart đơn giản và foolproof
- Hot-reload secrets tạo race windows cho lợi ích operational tối thiểu
- Viking hỗ trợ multiple simultaneous valid keys, enable rolling rotation mà không downtime
Operational procedure:
- Add new key vào Viking qua admin API
- Update team
.envvới new key - Roll restart OpenSpace instances (hoặc chỉ chờ CLI invocation tiếp theo)
- Remove old key khỏi Viking sau propagation
- OpenViking server chạy và
curl <URL>/healthreturn 200 -
OPENVIKING_URLset đúng (check port, TLS nếu applicable) -
OPENVIKING_API_KEYconfigure nếu Viking có auth enabled -
OPENVIKING_NAMESPACEset tới team identifier (hoặc cố ý empty cho single-user) -
OPENVIKING_USER_IDstrategy đã quyết định (auto-fallback vs explicit per-user) -
OPENVIKING_PUSH_SKILLSđánh giá theo privacy policy
# Verify client có thể reach Viking
python3 -c "
import asyncio
from openspace.viking import OpenVikingClient
async def check():
c = OpenVikingClient()
print('available:', await c.is_available())
print('namespace:', c.namespace)
print('user_id:', c.user_id)
print('agent tools uri:', c.agent_memory_uri('tools'))
print('user prefs uri:', c.user_memory_uri('preferences'))
await c.close()
asyncio.run(check())
"Expected output:
available: True
namespace: <namespace của bạn>
user_id: <user id của bạn>
agent tools uri: viking://tenants/<ns>/agent/memories/tools/
user prefs uri: viking://tenants/<ns>/user/<uid>/memories/preferences/
openspace --query "simple task to prime the memory base"Check logs:
tail -n 50 logs/openspace/*.log | grep "Viking"Mong đợi thấy:
✓ OpenViking integration active [namespace=..., user_id=...]
Viking telemetry: available=True hits=0 enrich_chars=0 feedback=committed pushed=1
Hits sẽ là 0 cho tới khi memory base populate. Điều này được mong đợi cho task đầu tiên.
Monitor các metrics này:
- Hit rate (
hits > 0): nên trend upward khi memory base grow - Feedback status: nên hầu hết là
committed—failedindicate Viking issues - Pushed skills: nên match evolved skill count khi push enabled
- Enrichment chars: range điển hình 500–2000; >3000 gợi ý memories quá verbose
63 tests covering mọi code path mới. Run qua:
python3 -m pytest tests/test_viking_client.py -v --asyncio-mode=auto| Area | Tests |
|---|---|
| Client graceful failure | 6 — unavailable server, find methods, session methods, skill push |
| Namespace URI building | 3 — combinations với/không namespace/user_id |
| Query composition | 4 — task-only, history merge, multimodal content, truncation |
| Health cache | 1 — TTL distinction cho success vs failure |
| Skill push | 3 — graceful fail, skip incomplete records, truthy response handling |
| Enrichment pipelines | 4 — empty retrieval, analysis context, history-aware, rich feedback |
| Identity resolution | 5 — overrides, env vars, OS user fallback, sanitization, empty state |
| Push opt-out env var | 3 — truthy/falsy/fallback to config |
| VikingExecutionStats | 2 — default shape, mutation isolation |
| Score threshold + resolvers (Round 6) | 7 — min score env override, clamping, fallback, scrub pii toggle, find propagation |
| PII scrubber (Round 6) | 12 — Anthropic/GitHub/AWS keys, email, basic-auth URL, JWT, private key block, CC Luhn, non-CC numbers, idempotence, None handling, nested records |
| Negative feedback + anti-patterns (Round 6) | 5 — graceful fail, antipatterns URI, stale memory report, antipattern key presence, env fingerprint shape |
| MCP tools (Round 6) | 8 — unavailable, missing query, no-client status, polarity validation, forget requires URI, category normalization, register count, tool_memory_status |
| Mid-iteration RetrieveMemoryTool (Round 6) | 3 — unavailable, empty query, tool shape |
Mọi test chạy chống port 127.0.0.1:19999 (cố ý unreachable). Điều này có nghĩa test suite:
- Pass bất kể OpenViking có chạy hay không
- Exercise failure path mà real deployments sẽ hit thường xuyên nhất
- Có sub-second total runtime (không network wait)
- Không bao giờ làm ô nhiễm real Viking instance
Integration tests chống real Viking instance không trong suite này — chúng nên sống trong directory riêng tests/integration/ guard bởi marker như @pytest.mark.viking_live và chạy chỉ trong CI với dedicated Viking container.
Cause: Client fail init. Thường một trong:
httpxkhông install (ModuleNotFoundError)OPENVIKING_URLxấu (không parse được)- Import error trong
openspace.viking.config(không chắc, nhưng check sanitization function)
Fix: Check .log file cho full stack. logger.debug chứa exception.
Cause: is_available() cached False result 12 giây.
Fix:
- Chờ 12 giây và retry
- Check
curl <OPENVIKING_URL>/healthtừ OpenSpace host trực tiếp - Check firewall / networking giữa OpenSpace và Viking
- Check Viking listen trên port mong đợi (1933 default)
Nếu curl work nhưng OpenSpace client không, check:
- Proxy environment variables (
HTTP_PROXY,HTTPS_PROXY) interfere - Different hostname resolution (ví dụ
localhostvs127.0.0.1)
Cause: Memory base empty hoặc queries không match.
Diagnosis:
# Check Viking có memories nào không
curl -X POST http://localhost:1933/api/v1/search/find \
-H "Content-Type: application/json" \
-d '{"query": "anything", "limit": 5}'Nếu empty, Viking chưa có extracted memories. Extraction là async — chờ sau vài task commits.
Nếu non-empty nhưng OpenSpace vẫn 0 hits:
- Check namespace match: OpenSpace query URI vs memory storage URI
curlvớitarget_uriexplicit match thứ OpenSpace gửi- Log
resolve_viking_identity()output để verify URI prefix nào dùng
Cause: Exception trong feedback session creation hoặc commit.
Diagnosis: Check .log cho OpenViking feedback skipped: <exception>. Causes thường gặp:
- Viking reject session format (không nên xảy ra với implementation hiện tại)
- Viking chậm và một trong messages timeout (5s per request)
- Viking return 4xx/5xx (check logs của chính Viking)
Fix: Thường transient. Nếu persistent:
- Tăng
_REQUEST_TIMEOUTtrongclient.py(không user-configurable; cần fork) - Check Viking disk / queue capacity
Cause: is_available() không được cache, hit /health per task.
Diagnosis: Nếu Viking keeps flapping available→unavailable, cache churn. Thường indicate chính Viking unhealthy hoặc network flaky.
Fix: Stabilize Viking. Cache TTL không thể giảm thêm mà không regression không chấp nhận được trên warm-cache hits.
Cause: Precedence order. OpenSpaceConfig.openviking_auto_push_skills=True + env var không parse đúng.
Diagnosis:
from openspace.viking.config import resolve_viking_push_enabled
print(resolve_viking_push_enabled(config_default=True))Nên print False nếu env var set đúng. Accepted values: 0 false no off.
Fix: Đảm bảo env var value chính xác là một trong các strings nhận diện được (case-insensitive). OPENVIKING_PUSH_SKILLS=no work; OPENVIKING_PUSH_SKILLS=NO work; OPENVIKING_PUSH_SKILLS=nope fallback về config default.
Expected behavior. OpenViking lưu memories (abstracts extracted từ sessions) độc lập với local skill DB của OpenSpace. Delete local skill không delete Viking memory của nó.
Cleanup: Dùng admin API của chính Viking để delete memories nếu cần, hoặc gọi openviking_forget_memory(uri) qua host agent MCP tool (Round 6). Điều này là cố ý — cross-agent propagation yêu cầu memories persist vượt qua bất kỳ local state của single agent.
Cause: Threshold cao hơn score thực tế của memory. Viking embedding similarity thường cho 0.3–0.8 cho good matches; set OPENVIKING_MIN_SCORE=0.9 sẽ drop gần như mọi thứ.
Diagnosis:
# Tạm disable threshold và check raw scores
OPENVIKING_MIN_SCORE=0.0 openspace --query "typical task"
# Inspect result["viking"]["hit_counts"] — nếu >0 giờ, threshold đã quá caoFix: Bắt đầu với OPENVIKING_MIN_SCORE=0.0 (default), observe score distribution vài ngày real workload, rồi tăng lên level drop chỉ bottom 10–20% hits.
Expected behavior. PII scrubber (OPENVIKING_SCRUB_PII=true, default) replace secrets, credentials, và PII bằng [REDACTED_*] placeholders trước khi ghi vào Viking. Điều này bảo vệ production secrets không leak vào shared memory.
Chỉ cho tests: set OPENVIKING_SCRUB_PII=false trong test environment nếu cần raw data round-trip qua Viking. Không bao giờ disable trong production.
Cause: Host agent's MCP client cache tool list lúc startup và chưa re-fetch sau khi Viking tools của OpenSpace được register.
Diagnosis:
- Check OpenSpace logs cho
Registered 5 OpenViking MCP tools for host agent access - Từ host agent, list MCP tools tường minh
- Verify
openviking_memory_status()return{"status": "ok"}khi gọi trực tiếp
Fix: Restart host agent để nó re-list MCP tools. Hầu hết hosts (Claude Code, Codex, OpenClaw) fetch list khi kết nối MCP server.
Cause: Hoặc Viking không được config (_viking_client là None), hoặc is_available() return False.
Diagnosis: Response dict bao gồm reason field:
result = await openspace.provide_feedback(task_id, "positive")
# {"status": "skipped", "reason": "OpenViking not configured"} hoặc
# {"status": "skipped", "reason": "OpenViking unavailable"}Fix: Verify Viking config giống "Tại sao Viking không làm gì cả?" ở trên.
Expected trong short tasks. Tool chỉ được register khi openviking_mid_iter_tool=True (default) và Viking client available. LLM quyết định khi nào gọi nó — nó KHÔNG gọi mỗi task, chỉ khi enrichment ban đầu không đủ.
Diagnosis: Check logs cho Added retrieve_memory tool (OpenViking mid-iteration). Nếu absent:
- Verify
config.openviking_mid_iter_toollàTrue - Verify Viking available trong OpenSpace initialization
- Check
openspace._grounding_agent._viking_clientkhông phảiNone
Nếu tool ĐƯỢC register nhưng không bao giờ được gọi: LLM judge enrichment ban đầu đã đủ. Đây là hành vi đúng. Tool tồn tại như safety valve cho case iter-1 hints misleading hoặc incomplete.
Nếu có gì đó sai và bạn cần disable Viking ngay:
# Option 1: Nhanh nhất — env var disable
export OPENVIKING_ENABLED=false
# Restart OpenSpace process
# Option 2: Config disable at source
# Trong OpenSpaceConfig: openviking_enabled=False
# Option 3: Nuclear — uninstall httpx
# Client._get_client() return None khi httpx missing → full graceful failOpenSpace sẽ chạy y hệt như trước integration. Không data loss, không migration cần thiết, không skill DB impact.
Để re-enable sau, flip env var back. Memories persist phía Viking và sẽ được find trên query đầu tiên sau re-enable.
Trước khi tuyên bố Viking "working" trong production, đo một trong:
# Tổng tasks
grep "Viking telemetry" logs/*.log | wc -l
# Tasks với ít nhất một hit
grep "Viking telemetry" logs/*.log | grep -v "hits=0" | wc -l
# Tính hit rate
echo "scale=2; $(grep 'Viking telemetry' logs/*.log | grep -v 'hits=0' | wc -l) / $(grep 'Viking telemetry' logs/*.log | wc -l)" | bcTarget: hit rate >30% sau tuần đầu sử dụng.
Run cùng task 10× với Viking enabled và 10× với OPENVIKING_ENABLED=false. Compare:
- Average
execution_timetrong result - Average iterations
- Token counts (từ recording metadata)
Mong đợi: warm-cache runs show 20–40% reduction trên cả hai dimensions.
Run GDPVal hoặc task suite nội bộ hai lần:
- Một lần với Viking disabled
- Một lần với Viking enabled (sau khi prime memory base)
Published OpenSpace number: 46% ít tokens hơn. Compound với Viking, mong đợi: 55–65% ít tokens hơn vs baseline (non-OpenSpace) agent.
Nếu bạn chạy Viking ở team scale, cân nhắc alert trên:
| Alert | Threshold | Action |
|---|---|---|
feedback_status=failed rate |
>5% trong 1h | Check Viking health, disk, queue |
available=False rate |
>10% trong 1h | Check Viking uptime / networking |
hits=0 rate |
>70% sau 1 tuần | Investigate memory extraction pipeline |
pushed_skills monotonic decline |
Downward trend trong 7d | Check xem push_skills env var có bị flip off |
Mean enrichment_chars |
>5000 | Memory bloat — cân nhắc Viking-side cleanup |
Các này derive từ per-execution viking stats dict. Pipe tới observability stack của bạn (Prometheus, Datadog, CloudWatch, v.v.) qua metrics exporter — không built vào OpenSpace.
Ngày 1 (bootstrapping):
available=Truetrên hầu hết tasks → integration đang workhits=0trên hầu hết tasks → memory base empty, đây là đúngfeedback=committedtrên tasks với evolution → Viking nhận feedback
Ngày 7:
hits>0trên một số tasks → memory extraction đã catch up- First signs của iteration reduction trên repeated task patterns
- Bắt đầu thấy selector pick skills khác so với không có hints
Ngày 30:
- Stable hit rate 30–60% tùy vào task diversity
- Iteration/token reduction có thể đo được vs baseline
- User preferences bắt đầu shape agent behavior mà không cần explicit prompts
- Benchmark runs cần raw agent performance
- Tasks với strict determinism requirements
- Privacy-sensitive one-off tasks mà kể cả extracted abstracts không được rời execution
- Single-task pipelines mà chi phí populate memory vượt quá savings
- Debugging sessions mà learned state làm confuse signal
Với mọi thứ khác, giữ nó on. Failure mode là "integration vô hình", không phải "integration break OpenSpace".
Quay lại: Index · Kiến trúc · Token Economics · Configuration