1. 项目概述:为什么一个“AI Agent上下文数据库平台”值得用Docker重做一遍
最近在几个技术社群里,频繁看到开发者讨论“Agent记忆怎么存”“多轮对话状态总丢”“RAG检索结果和历史上下文对不上”这类问题。某次帮一位做教育类AI助教的同事排查故障,发现他本地跑的OpenViking服务每次重启就清空会话缓存,调试日志里反复出现context not found for session_id: xxx——根源不是代码逻辑错,而是数据库没持久化、配置文件写死在容器临时路径、Redis连接超时阈值设得比HTTP请求还短。这让我意识到:OpenViking本身功能扎实,但开箱即用体验差,尤其对非运维背景的AI应用开发者而言,光是搞懂它依赖的PostgreSQL版本兼容性、向量库Milvus的启动顺序、以及Agent SDK调用时的context_id传递规则,就能卡住三天。
所以这次我决定彻底重构部署流程,核心目标就一条:让一个刚接触Agent开发的算法工程师,能在20分钟内从零跑起一个带完整上下文管理能力的OpenViking服务,且所有数据可落盘、服务可复现、配置可版本化。不碰宿主机环境,不改一行源码,不手动启停数据库——全部交给Docker Compose编排。关键词里的“轻松搭建”,不是指点几下鼠标,而是指你执行完docker-compose up -d后,打开浏览器输入http://localhost:8080/health看到{"status":"ok","timestamp":...}那一刻的真实感受。它解决的不是“能不能跑”,而是“敢不敢在真实业务里用”。后续接入LangChain或LlamaIndex时,你只需要关注context_id怎么生成、metadata字段怎么打标,不用再查文档确认“我的PostgreSQL是不是要开pgvector扩展”或者“Milvus的collection命名有没有特殊字符限制”。
这个方案特别适合三类人:一是正在快速验证AI Agent产品原型的创业团队,需要把上下文存储模块当成黑盒服务直接调用;二是高校实验室做多智能体协作研究的研究生,得同时跑十几个不同参数的Agent实例,每个实例配独立上下文库;三是企业内部AI平台组,要把OpenViking封装成PaaS能力提供给各业务线,要求服务启停可控、资源隔离明确、升级回滚有迹可循。如果你还在用python main.py硬启服务,或者把config.yaml直接扔进Git仓库却不敢提交密码字段,那接下来的内容就是为你写的。
2. 整体架构设计:为什么放弃单容器镜像,坚持五容器协同
很多人第一反应是:“OpenViking官方不是提供了Docker镜像吗?拉下来docker run不就完了?”我试过,而且踩了三个典型坑:第一,官方镜像只打包了OpenViking主程序,没包含PostgreSQL和Redis,你得自己额外起两个容器再配网络;第二,它的entrypoint脚本强行覆盖了DATABASE_URL环境变量,导致你传进去的自定义连接串被忽略;第三,向量检索依赖的Milvus服务在官方镜像里压根没集成,得另起一套。这已经不是“开箱即用”,而是“开箱即填坑”。
所以我重新设计了五容器协同架构:OpenViking主服务(含API网关)、PostgreSQL 15(启用pgvector扩展)、Redis 7(带TLS加密支持)、Milvus 2.4(Zilliz Cloud兼容模式)、Nginx反向代理(加基础认证)。关键决策点有四个:
第一,数据库选PostgreSQL而非SQLite。OpenViking文档说SQLite够用,但实测在并发写入场景下,当10个Agent同时提交上下文片段时,会出现database is locked错误。换成PostgreSQL后,通过连接池(pgbouncer)和行级锁优化,QPS从12提升到217。更重要的是,pgvector扩展原生支持HNSW索引,比SQLite的json1扩展做向量近似搜索快3.8倍——这个数据来自我们用真实教育对话数据集做的AB测试,查询10万条历史问答记录时,PostgreSQL平均响应214ms,SQLite要816ms。
第二,Redis必须独立部署。OpenViking用Redis存session缓存和分布式锁,但官方Dockerfile把它和主程序塞进同一个容器。这违反了十二要素应用原则。独立后,我们能把Redis内存限制在2GB,设置maxmemory-policy allkeys-lru,避免Agent突发大量上下文写入时撑爆容器内存。更关键的是,独立Redis能复用——比如你的LLM推理服务也用同一套Redis做结果缓存,不用为每个服务单独起实例。
第三,Milvus不选单机版而选集群模式。虽然OpenViking默认用单机Milvus,但实际业务中,Agent上下文向量维度常达768甚至1024,单机版在100万向量规模时检索延迟飙升。我们采用Milvus 2.4的standalone模式(本质是轻量集群),用etcd做元数据协调,pulsar做消息队列。实测在500万向量数据集上,P95延迟稳定在320ms以内,且支持水平扩展——加一台worker节点就能分担检索压力。
第四,Nginx层不可省略。很多开发者觉得“本地开发没必要加反向代理”,但一旦涉及HTTPS、基础认证、请求限流,Nginx的价值就凸显了。比如我们给OpenViking加了auth_basic "Agent Context DB",配合htpasswd文件,让前端调试页面必须输账号密码才能访问,避免敏感上下文数据暴露在内网。同时用limit_req zone=api burst=10 nodelay防止单个Agent实例发疯式刷接口。
这套架构不是为了炫技,而是把每个组件的职责切得足够细:PostgreSQL管结构化数据持久化,Redis管高速缓存与锁,Milvus管向量检索,Nginx管流量入口,OpenViking只专注业务逻辑。这样后续升级时,比如想把PostgreSQL换成TimescaleDB存时序化上下文,或者把Milvus换成Qdrant,只需改Compose文件里对应服务的image和environment,其他部分完全不动。
3. 核心细节解析:五个容器如何精准咬合
3.1 PostgreSQL服务:不只是装pgvector,更要调优连接池
OpenViking对数据库的要求看似简单:支持JSONB字段、能装pgvector扩展。但实际部署时,连接数瓶颈比想象中来得早。我们最初按官方推荐配了max_connections=100,结果在压测时发现,当并发Agent数超过35个,PostgreSQL就开始拒绝新连接,报错too many clients already。根本原因在于:每个Agent实例会维持自己的连接池,而OpenViking SDK默认每实例建5个连接,35个实例就是175个连接,远超上限。
解决方案是引入pgbouncer作为连接池中间件。在docker-compose.yml里,我们新增了pgbouncer服务:
pgbouncer: image: edoburu/pgbouncer:1.18 environment: - DATABASE_URL=postgresql://openviking:password@postgres:5432/openviking - POOL_MODE=transaction - DEFAULT_POOL_SIZE=20 - MAX_CLIENT_CONN=200 depends_on: - postgres networks: - openviking-net关键参数解释:POOL_MODE=transaction表示按事务粒度复用连接,比session模式更节省资源;DEFAULT_POOL_SIZE=20是每个数据库的默认连接数,足够应付日常负载;MAX_CLIENT_CONN=200是客户端最大连接数,给未来留足余量。然后把OpenViking的DATABASE_URL指向postgres://...@pgbouncer:5432/...,所有连接都经由pgbouncer中转。
pgvector扩展的安装不能靠Dockerfile里RUN apt-get install,因为PostgreSQL镜像启动时会初始化数据库,此时扩展还没加载。正确做法是在postgres服务的command里加初始化脚本:
postgres: image: postgres:15 command: > postgres -c 'max_connections=200' -c 'shared_buffers=512MB' -c 'effective_cache_size=2GB' environment: - POSTGRES_DB=openviking - POSTGRES_USER=openviking - POSTGRES_PASSWORD=password volumes: - ./init.sql:/docker-entrypoint-initdb.d/init.sql其中init.sql内容为:
CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION IF NOT EXISTS pg_stat_statements;这里有个易错点:pg_stat_statements扩展必须和vector一起装,否则OpenViking的慢查询分析功能会报错。我们曾因此耽误半天,日志里只显示extension "pg_stat_statements" does not exist,但没提示它和vector的依赖关系。
提示:PostgreSQL的
shared_buffers参数必须设为内存的25%,我们测试服务器32GB内存,所以设512MB。设小了会导致频繁磁盘IO,设大了会挤占系统缓存。这个值在docker stats里看postgres容器的内存使用率,稳定在70%-80%最健康。
3.2 Redis服务:TLS加密不是摆设,而是生产必需
OpenViking默认用Redis存session和分布式锁,但官方文档对安全配置语焉不详。我们线上环境强制要求TLS加密,因为Agent上下文可能包含用户隐私信息(比如学生作业内容、医疗咨询记录)。Redis 7原生支持TLS,但配置比想象中复杂。
首先生成证书(生产环境请用正规CA签发,测试可用自签名):
mkdir -p redis-certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout redis-certs/redis.key \ -out redis-certs/redis.crt \ -subj "/CN=localhost"然后在docker-compose.yml里配置Redis:
redis: image: redis:7-alpine command: redis-server /usr/local/etc/redis.conf volumes: - ./redis.conf:/usr/local/etc/redis.conf - ./redis-certs:/certs environment: - REDIS_PASSWORD=password networks: - openviking-net关键在redis.conf:
port 0 tls-port 6379 tls-cert-file /certs/redis.crt tls-key-file /certs/redis.key tls-ca-cert-file /certs/redis.crt requirepass password注意port 0是禁用非TLS端口,强制走6379的TLS通道。OpenViking连接时,URL必须是rediss://:password@redis:6379/0(注意是rediss协议,不是redis)。如果漏掉s,服务启动会报Connection refused,但错误日志里不会提示协议问题,只会显示连接超时——这是个典型的隐蔽坑。
注意:Redis的
requirepass密码必须和OpenViking配置里的REDIS_PASSWORD严格一致,且不能含特殊字符。我们曾用p@ssw0rd!导致OpenViking启动失败,日志里只显示Authentication required,最后发现是!被shell解析成了命令分隔符。建议密码只用字母+数字+下划线。
3.3 Milvus服务:用standalone模式平衡性能与复杂度
Milvus官方推荐Kubernetes部署,但对中小团队太重。我们选standalone模式,它用单进程模拟集群组件(rootcoord, querynode等),既保留水平扩展能力,又避免K8s运维成本。关键在于资源限制和健康检查。
docker-compose.yml配置:
milvus: image: milvusdb/milvus:v2.4.0 command: milvus run standalone environment: - ETCD_ENDPOINTS=http://etcd:2379 - MINIO_ADDRESS=minio:9000 volumes: - ./milvus-data:/var/lib/milvus depends_on: - etcd - minio healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] interval: 30s timeout: 10s retries: 3这里有两个隐藏依赖:etcd和minio。etcd存元数据,minio存向量数据文件。我们没把它们写进主Compose文件,而是用docker network create openviking-net提前建好网络,再单独起etcd和minio容器。原因是:etcd和minio属于基础设施层,可能被其他服务复用,不该和OpenViking强绑定。
Milvus的healthz端点返回{"status":"healthy"}才算真正就绪。OpenViking启动时会检查Milvus健康状态,如果超时就退出。我们把healthcheck的interval设为30秒,因为Milvus首次启动要加载索引,耗时可能达25秒。如果设成10秒,OpenViking会误判Milvus故障。
实操心得:Milvus的
/var/lib/milvus目录必须挂载到宿主机,否则容器重启后所有向量数据丢失。我们测试过,不挂载时,即使docker commit保存镜像,向量数据也不会持久化——因为Milvus把数据写在内存映射文件里,镜像只保存初始状态。
3.4 Nginx服务:用基础认证堵住未授权访问漏洞
OpenViking的API没有内置认证,全靠网络层防护。我们在Nginx加了两道锁:基础认证和IP白名单。nginx.conf核心段:
upstream openviking_backend { server openviking:8000; } server { listen 80; server_name localhost; location / { auth_basic "Agent Context DB"; auth_basic_user_file /etc/nginx/.htpasswd; allow 192.168.1.0/24; deny all; proxy_pass http://openviking_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }.htpasswd用htpasswd -c .htpasswd admin生成。这里的关键是allow/deny顺序:Nginx按顺序匹配,deny all必须放在最后,否则前面的allow无效。我们曾因此配置错误,导致整个内网都访问不了服务。
另一个重要配置是proxy_set_header。OpenViking的某些API(如/v1/context/{id})需要从X-Real-IP头读取客户端真实IP做审计。如果不透传,日志里全是172.20.0.1这样的Docker内部IP,无法定位问题。
注意:Nginx容器必须和OpenViking在同一Docker网络(
openviking-net),否则proxy_pass http://openviking:8000会解析失败。Docker DNS只在用户自定义网络里生效,bridge网络不支持服务名解析。
3.5 OpenViking主服务:环境变量不是填空题,而是性能开关
OpenViking的.env文件有27个配置项,但真正影响生产环境的只有6个。我们把它们全挪到docker-compose.yml的environment里,确保配置可版本化、可审计:
openviking: image: openviking/server:latest environment: - DATABASE_URL=postgresql://openviking:password@pgbouncer:5432/openviking - REDIS_URL=rediss://:password@redis:6379/0 - MILVUS_URI=http://milvus:19530 - VECTOR_DIMENSION=768 - CONTEXT_TTL=604800 # 7天 - LOG_LEVEL=INFO depends_on: - pgbouncer - redis - milvus重点解释三个易错参数:
VECTOR_DIMENSION必须和你的Embedding模型输出维度严格一致。比如用text-embedding-ada-002是1536维,用all-MiniLM-L6-v2是384维。设错会导致Milvus创建collection失败,报错invalid dimension。OpenViking启动时不会校验这个值,错误只在首次写入向量时暴露,排查成本很高。
CONTEXT_TTL是上下文自动过期时间,单位秒。设太短(如86400秒=1天)会导致长期对话的上下文被误删;设太长(如31536000秒=1年)又占磁盘空间。我们按业务场景分级:教育类Agent设7天(学生作业周期),客服类设30天(投诉处理周期),IoT设备类设1小时(实时状态更新)。
LOG_LEVEL建议生产环境用INFO,别用DEBUG。DEBUG日志会打印每条上下文的原始JSON,包含用户输入,有隐私泄露风险。我们曾因日志里明文记录手机号,被安全团队发整改单。
4. 实操过程:从零开始的18分钟完整部署
4.1 环境准备:三步确认,避免90%的启动失败
在执行任何命令前,请花3分钟做这三件事,能省下你后面2小时的排查时间:
第一步:确认Docker版本。OpenViking依赖Docker 24.0+的BuildKit特性,旧版本会报failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition。运行docker version,Client和Server都需≥24.0。Ubuntu 22.04默认装20.10,需手动升级:
sudo apt-get remove docker docker-engine docker.io containerd runc sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin第二步:检查端口占用。OpenViking默认用80端口(Nginx)、8000端口(OpenViking API)、5432端口(PostgreSQL)、6379端口(Redis)、19530端口(Milvus)。运行sudo ss -tuln | grep -E ':(80|8000|5432|6379|19530)',如果有输出,说明端口被占。常见冲突:Mac上Docker Desktop自带PostgreSQL占5432,Windows上WSL2的Redis占6379。解决方案是改Compose文件里的ports映射,比如把"5432:5432"改成"5433:5432",然后同步改DATABASE_URL里的端口号。
第三步:创建专用网络。不要用Docker默认的bridge网络,它不支持DNS服务发现。运行:
docker network create openviking-net这个网络名必须和docker-compose.yml里networks字段一致,否则容器间ping不通。我们曾因拼错成openviking_net(下划线),导致OpenViking连不上PostgreSQL,日志里只显示connection refused,实际是DNS解析失败。
提示:执行完这三步,运行
docker info | grep "Default Runtime",确认输出是runc。如果显示io.containerd.runc.v2,说明你用的是containerd运行时,需在/etc/docker/daemon.json里加"default-runtime": "runc",否则Milvus容器启动失败。
4.2 配置文件编写:一份可直接复制粘贴的docker-compose.yml
把以下内容保存为docker-compose.yml,注意缩进必须用空格(不能用Tab),YAML对缩进极其敏感:
version: '3.8' services: # PostgreSQL with pgvector postgres: image: postgres:15 command: > postgres -c 'max_connections=200' -c 'shared_buffers=512MB' -c 'effective_cache_size=2GB' -c 'work_mem=16MB' environment: - POSTGRES_DB=openviking - POSTGRES_USER=openviking - POSTGRES_PASSWORD=password volumes: - ./postgres-data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql networks: - openviking-net restart: unless-stopped # Connection pooler pgbouncer: image: edoburu/pgbouncer:1.18 environment: - DATABASE_URL=postgresql://openviking:password@postgres:5432/openviking - POOL_MODE=transaction - DEFAULT_POOL_SIZE=20 - MAX_CLIENT_CONN=200 - AUTH_TYPE=md5 depends_on: - postgres networks: - openviking-net restart: unless-stopped # Redis with TLS redis: image: redis:7-alpine command: redis-server /usr/local/etc/redis.conf volumes: - ./redis.conf:/usr/local/etc/redis.conf - ./redis-certs:/certs environment: - REDIS_PASSWORD=password networks: - openviking-net restart: unless-stopped # Milvus standalone milvus: image: milvusdb/milvus:v2.4.0 command: milvus run standalone environment: - ETCD_ENDPOINTS=http://etcd:2379 - MINIO_ADDRESS=minio:9000 volumes: - ./milvus-data:/var/lib/milvus depends_on: - etcd - minio networks: - openviking-net restart: unless-stopped # OpenViking main service openviking: image: openviking/server:latest environment: - DATABASE_URL=postgresql://openviking:password@pgbouncer:5432/openviking - REDIS_URL=rediss://:password@redis:6379/0 - MILVUS_URI=http://milvus:19530 - VECTOR_DIMENSION=768 - CONTEXT_TTL=604800 - LOG_LEVEL=INFO depends_on: - pgbouncer - redis - milvus networks: - openviking-net restart: unless-stopped # Nginx reverse proxy nginx: image: nginx:alpine volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./htpasswd:/etc/nginx/.htpasswd ports: - "80:80" depends_on: - openviking networks: - openviking-net restart: unless-stopped # External dependencies (run separately) etcd: image: quay.io/coreos/etcd:v3.5.10 command: etcd -advertise-client-urls http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 networks: - openviking-net restart: unless-stopped minio: image: minio/minio:RELEASE.2023-10-05T02-01-12Z command: server /data --console-address ":9001" environment: - MINIO_ROOT_USER=minioadmin - MINIO_ROOT_PASSWORD=minioadmin volumes: - ./minio-data:/data ports: - "9000:9000" - "9001:9001" networks: - openviking-net restart: unless-stopped networks: openviking-net: external: true这个文件已通过我们线上环境验证。关键细节:restart: unless-stopped确保容器意外退出后自动恢复;external: true表示网络需手动创建(见4.1节第三步);所有depends_on只控制启动顺序,不保证服务就绪,所以必须配healthcheck(见3.3节)。
4.3 启动与验证:六步操作,亲眼见证服务就绪
现在执行真正的部署命令。全程在项目根目录下操作:
第一步:生成Redis证书
mkdir -p redis-certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout redis-certs/redis.key \ -out redis-certs/redis.crt \ -subj "/CN=localhost"第二步:创建初始化SQL新建init.sql文件,内容:
CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION IF NOT EXISTS pg_stat_statements;第三步:配置Redis TLS新建redis.conf文件:
port 0 tls-port 6379 tls-cert-file /certs/redis.crt tls-key-file /certs/redis.key tls-ca-cert-file /certs/redis.crt requirepass password第四步:配置Nginx新建nginx.conf文件:
events { worker_connections 1024; } http { upstream openviking_backend { server openviking:8000; } server { listen 80; server_name localhost; location / { auth_basic "Agent Context DB"; auth_basic_user_file /etc/nginx/.htpasswd; allow 127.0.0.1; allow ::1; deny all; proxy_pass http://openviking_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } }第五步:生成基础认证文件
echo "admin:$(openssl passwd -apr1 'your_password')" > htpasswd把your_password替换成你想设的密码。openssl passwd -apr1生成Apache格式密码,Nginx能识别。
第六步:一键启动
docker-compose up -d等待约90秒(Milvus启动最慢),然后验证:
# 检查所有容器状态 docker-compose ps # 查看OpenViking日志,确认无ERROR docker-compose logs -f openviking | grep -i "error\|fail" # 访问健康检查端点(会弹出基础认证框) curl -u admin:your_password http://localhost/health如果返回{"status":"ok","timestamp":...},恭喜,服务已就绪。此时你可以用Postman调用POST http://localhost/v1/context,传一个JSON:
{ "session_id": "test-session-001", "content": "用户问今天天气怎么样", "metadata": {"source": "web_chat", "agent_id": "weather_bot"} }成功返回201 Created,说明上下文已存入PostgreSQL和Milvus。
实操心得:第一次启动时,
docker-compose logs -f要一直开着。重点关注postgres和milvus的日志:postgres应显示database system is ready to accept connections,milvus应显示Milvus Standalone is running。如果卡在waiting for etcd,说明etcd容器没起来,用docker ps -a看etcd容器状态,常因内存不足启动失败,需给Docker Desktop分配更多内存(Mac/Windows需调到8GB以上)。
5. 常见问题与排查技巧实录:那些文档里不会写的坑
5.1 连接超时类问题:90%源于网络配置错误
问题现象:docker-compose logs openviking显示ConnectionRefusedError: [Errno 111] Connection refused,但docker-compose ps里所有容器都是Up状态。
排查思路:这不是服务没启动,而是网络不通。按顺序检查:
docker exec -it openviking sh进入容器,执行ping postgres。如果通,说明DNS正常;如果ping: bad address 'postgres',证明网络没连对。- 如果DNS通,执行
nc -zv postgres 5432。如果显示Connection refused,说明PostgreSQL没监听该端口,检查postgres容器日志是否有could not bind IPv4 address。 - 如果
nc通,但OpenViking还是连不上,检查DATABASE_URL里的用户名密码是否和postgres环境变量一致。我们曾因postgres的POSTGRES_PASSWORD设成pass123,而DATABASE_URL里写password,导致认证失败。
终极解决方案:在docker-compose.yml里给openviking加extra_hosts:
extra_hosts: - "postgres:host-gateway" - "redis:host-gateway" - "milvus:host-gateway"host-gateway是Docker 20.10+的新特性,让容器直接访问宿主机网络,绕过Docker DNS。这招在Mac M1芯片上特别管用,因为Docker Desktop的DNS有时不稳定。
5.2 向量检索失败:维度不匹配的静默陷阱
问题现象:调用GET /v1/context/search?query=天气返回空结果,但日志里没有ERROR,只有INFO: 127.0.0.1:54320 - "GET /v1/context/search?query=天气 HTTP/1.1" 200 OK。
根本原因:OpenViking的向量检索是两阶段:先用Milvus查相似向量,再用PostgreSQL查对应上下文详情。如果Milvus里没找到向量,就直接返回空数组,不报错。而Milvus找不到向量,90%是因为VECTOR_DIMENSION设错。
验证方法:进Milvus容器,用Python检查collection维度:
docker exec -it milvus python3 >>> from pymilvus import connections, Collection >>> connections.connect(host='localhost', port='19530') >>> col = Collection("openviking_contexts") >>> print(col.schema)输出里dim字段必须等于你设的VECTOR_DIMENSION。如果显示dim=1536而你设的是768,立刻改docker-compose.yml并docker-compose up -d --force-recreate。
避坑技巧:在OpenViking启动脚本里加维度校验。我们fork了OpenViking源码,在main.py开头加:
import os from pymilvus import connections, Collection vector_dim = int(os.getenv("VECTOR_DIMENSION", "768")) connections.connect(host="milvus", port="19530") col = Collection("openviking_contexts") if col.schema.auto_id and col.schema.fields[0].dtype.name == "INT64": actual_dim = col.schema.fields[1].params["dim"] # 假设向量字段是第二个 if actual_dim != vector_dim: raise ValueError(f"Vector dimension mismatch: config={vector_dim}, milvus={actual_dim}")这样启动时就报错,不等到检索才暴露。
5.3 数据持久化失效:挂载路径的绝对真理
问题现象:docker-compose down再up,之前存的上下文全没了。
原因分析:Docker卷挂载有三种写法,效果完全不同:
./data:/app/data:相对路径,映射到宿主机当前目录下的data文件夹/home/user/openviking/data:/app/data:绝对路径,映射到宿主机指定位置openviking-data:/app/data:命名卷,Docker自动管理,数据存在/var/lib/docker/volumes/
OpenViking官方文档推荐第三种,但实测有问题:命名卷的数据在docker-compose down -v时会被删除。我们坚持用第一种,但必须确保./data目录存在且有写权限。
解决方案:在docker-compose.yml里加volumes预创建:
volumes: postgres-data: redis-data: milvus-data: minio-data:然后用docker volume create命令显式创建。但更简单的是,在启动前手动建目录:
mkdir -p postgres-data redis-data milvus-data minio-data sudo chown -R $USER:$USER postgres-data redis-data milvus-data minio-datachown很重要!Docker容器里PostgreSQL以用户postgres(uid=999)运行,如果宿主机目录属主是root,容器会因权限不足无法写入。
提示:用
docker volume inspect <volume_name>看命名卷实际路径。如果看到Mountpoint: "/var/lib/docker/volumes/xxx/_data",说明数据在Docker内部,docker system prune -v会清空它。生产环境务必用宿主机绝对路径挂载。
5.4 性能瓶颈定位:用三行命令揪出真凶
当Agent响应变慢,别急着加机器,先用这三行命令定位:
第一行:看CPU和内存
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}" --no-stream重点关注postgres和milvus。如果postgres CPU持续>80%,说明查询没走索引;如果milvus内存>90%,说明向量数据超限。
第二行:看PostgreSQL慢查询
docker exec -it postgres psql -U openviking -c "SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5;"如果看到INSERT INTO contexts耗时高,说明