上一篇Building KnowledgeBase with Opencode我记录了一个比较轻量的知识库冷启动方案:用 OpenCode Web 作为知识库草稿整理工作台,用 Git 管理知识源文件,用 AGENTS.md / skills / commands / permissions 约束格式、流程和安全边界。
下一篇:Building KnowledgeBase with OpenCode 3 - CC Connect。
上一篇的方案可以支撑第一版 POC,但继续往前走时,我遇到了两个新的问题:
1. OpenCode Web 缺少文件上传入口
2. OpenCode Web 的权限范围接近运行它的 Linux 用户OpenCode Web 可以整理知识库草稿,但缺少自然的 raw files 上传入口;直接裸跑在宿主机上,也会让它的权限范围接近运行它的 Linux 用户。
所以这篇是上一篇的补充:用 Docker 封装 OpenCode Web,并用 SFTPGo WebClient 提供文件上传入口。
最终目标是把它升级成:
OpenCode Web + SFTPGo WebClient 的项目级知识库 agent 工作区1. 这次升级解决什么问题
这次升级的目标是:
1. 给同事一个浏览器文件上传入口
2. 把上传文件统一放到 inbox/uploaded-docs/
3. 让 OpenCode Web 只看到项目目录
4. 保持原来的 AGENTS.md / skills / commands / Git review 结构不变
5. 尽量小改动,不重做整套系统2. 新架构
升级后,结构变成:
业务同事
├── SFTPGo WebClient
│ ↓
│ 上传 raw files
│ ↓
│ /srv/company-kb/inbox/uploaded-docs/
│
└── OpenCode Web
↓
读取 inbox/uploaded-docs/
↓
生成 review/pending/*.md
↓
人工 review
↓
knowledge/ 或 review/approved/容器视角是:
Host:
/srv/company-kb/
OpenCode container:
/workspace -> /srv/company-kb/
SFTPGo container:
upload dir -> /srv/company-kb/inbox/uploaded-docs/之前 OpenCode Web 直接运行在宿主机上,理论上可能接触到服务器上的更多路径。现在它运行在 Docker 容器里,只挂载 /srv/company-kb 到容器内的 /workspace。
这个 agent 的工作范围收敛到:
/workspace这更接近我想要的“项目级 agent”。
3. 保留原来的 company-kb repo
这次升级不需要重建知识库 repo。
继续使用:
/srv/company-kb/原来的结构继续保留:
company-kb/
├── AGENTS.md
├── opencode.jsonc
├── README.md
├── START_HERE.md
├── inbox/
│ └── uploaded-docs/
├── knowledge/
├── review/
│ └── pending/
├── scripts/
│ └── validate_kb.py
└── .opencode/
├── commands/
│ └── kb-start.md
└── skills/只是把运行方式从宿主机 systemd 改成 Docker Compose。
4. 停掉旧的 systemd 服务
如果之前是用 systemd 托管 OpenCode Web,可以先停掉。
例如服务名是:
opencode-kb-web.service执行:
sudo systemctl stop opencode-kb-web
sudo systemctl disable opencode-kb-web不建议立刻删除 service 文件。这样如果 Docker 方案出问题,还可以快速回滚:
cd /opt/kb-agent-stack
sudo docker compose down
sudo systemctl enable --now opencode-kb-web5. 准备 Docker Compose 目录
新建一个独立的 stack 目录:
sudo mkdir -p /opt/kb-agent-stack/opencode
sudo mkdir -p /opt/kb-agent-stack/opencode-home
sudo mkdir -p /opt/kb-agent-stack/sftpgo-data
sudo mkdir -p /srv/company-kb/inbox/uploaded-docs这里几个目录的作用是:
/opt/kb-agent-stack/
存放 Docker Compose 和容器相关配置
/opt/kb-agent-stack/opencode-home/
持久化 OpenCode 容器里的 home,包括 auth 等状态
/opt/kb-agent-stack/sftpgo-data/
持久化 SFTPGo 数据
/srv/company-kb/
真实知识库 repo
/srv/company-kb/inbox/uploaded-docs/
SFTPGo 上传文件落地目录6. OpenCode Dockerfile
我这里没有使用一个复杂的自定义镜像,只做一个很薄的 Node 镜像,然后安装 opencode。
创建:
nano /opt/kb-agent-stack/opencode/Dockerfile写入:
FROM node:22-bookworm-slim
RUN apt-get update && apt-get install -y \
bash \
curl \
git \
ca-certificates \
python3 \
jq \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g opencode-ai
RUN groupadd -g 10001 opencode \
&& useradd -m -u 10001 -g 10001 -s /bin/bash opencode \
&& mkdir -p /workspace \
&& chown -R opencode:opencode /workspace /home/opencode
USER opencode
ENV HOME=/home/opencode
WORKDIR /workspace
EXPOSE 4096
CMD ["opencode", "web", "--hostname", "0.0.0.0", "--port", "4096"]几个要点:
1. OpenCode 在容器里运行
2. 默认工作目录是 /workspace
3. 运行用户不是 root
4. /workspace 会挂载到宿主机 /srv/company-kb7. OpenCode 环境变量
创建:
nano /opt/kb-agent-stack/.env.opencode写入:
OPENCODE_SERVER_USERNAME=opencode
OPENCODE_SERVER_PASSWORD=change-this-to-a-strong-password权限收紧:
sudo chmod 600 /opt/kb-agent-stack/.env.opencode模型凭据有两种做法:
1. 在容器里重新执行 opencode auth login / /connect
2. 通过环境变量提供 provider API key我最后采用的是在容器中重新完成 OpenCode 登录配置。因为 /home/opencode 已经被挂载到宿主机的 opencode-home/,所以容器重启后认证状态不会丢。
8. docker-compose.yml
创建:
nano /opt/kb-agent-stack/docker-compose.yml写入:
services:
opencode-web:
build:
context: ./opencode
container_name: kb-opencode-web
restart: unless-stopped
working_dir: /workspace
env_file:
- ./.env.opencode
environment:
HOME: /home/opencode
ports:
- "4096:4096"
volumes:
- /srv/company-kb:/workspace
- ./opencode-home:/home/opencode
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
sftpgo:
image: drakkan/sftpgo:latest
container_name: kb-sftpgo
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./sftpgo-data:/var/lib/sftpgo
- /srv/company-kb/inbox/uploaded-docs:/srv/sftpgo/data/uploads
environment:
SFTPGO_HTTPD__BINDINGS__0__PORT: "8080"
SFTPGO_HOOK__DISABLE_DOT_ENTRIES: "1"
security_opt:
- no-new-privileges:trueSFTPGo 的职责非常窄:
只负责 WebClient 上传文件
不负责知识整理
不负责 RAG
不负责审核9. 启动服务
执行:
cd /opt/kb-agent-stack
sudo docker compose build
sudo docker compose up -d检查:
sudo docker compose ps
sudo docker compose logs -f opencode-web
sudo docker compose logs -f sftpgo访问:
OpenCode Web:
http://SERVER_IP:4096
SFTPGo:
http://SERVER_IP:8080SFTPGo 管理入口一般是:
http://SERVER_IP:8080/web/adminSFTPGo 普通用户 WebClient 入口一般是:
http://SERVER_IP:8080/web/client10. 配置 SFTPGo WebClient
第一次进入 SFTPGo admin 后,创建 admin 用户。
然后创建一个普通上传用户,例如:
username: kb-uploader
home dir: /srv/sftpgo/data/uploads这个 home dir 是容器内路径,实际映射到宿主机:
/srv/company-kb/inbox/uploaded-docs/所以同事通过 SFTPGo WebClient 上传文件后,宿主机可以看到:
ls -la /srv/company-kb/inbox/uploaded-docsOpenCode 容器内也能看到:
ls -la /workspace/inbox/uploaded-docs这条链路就是:
SFTPGo WebClient
↓
/srv/company-kb/inbox/uploaded-docs
↓
OpenCode container: /workspace/inbox/uploaded-docs11. 配置 OpenCode 模型
进入 OpenCode 容器:
cd /opt/kb-agent-stack
sudo docker compose exec opencode-web bash容器内确认当前目录:
cd /workspace
pwd应该是:
/workspace然后配置 OpenCode:
opencode auth login或者进入 TUI / Web 后执行:
/connect
/models这里有一个重要细节:Docker 方案下,OpenCode Web 中应该选择 /workspace 作为项目工作区。
宿主机上的:
/srv/company-kb只是 Docker bind mount 的来源路径。
容器里的项目路径才是:
/workspace如果在 OpenCode Web 里还打开旧路径 /srv/company-kb,就可能出现:
AGENTS.md 没加载
.opencode/commands 没发现
/kb-start 不出现
skills 行为不稳定根因通常是当前 session 打开的 workspace 不对。
12. 验证 workspace
进入容器:
cd /opt/kb-agent-stack
sudo docker compose exec opencode-web bash检查:
cd /workspace
pwd
git status
ls -la .opencode
ls -la .opencode/commands
cat .opencode/commands/kb-start.md理想结果:
/workspace
.git 存在
.opencode/commands/kb-start.md 存在
AGENTS.md 存在
START_HERE.md 存在
opencode.jsonc 存在然后在 OpenCode Web 里:
1. 选择 /workspace 作为 project
2. 新建 session
3. 输入 /kb-start如果 /kb-start 仍然不出现,先不要急着改配置。优先确认当前 Web session 是否真的是 /workspace。
13. Git dubious ownership 问题
容器化之后,可能会遇到宿主机运行 Git 时的错误:
fatal: detected dubious ownership in repository at '/srv/company-kb'这是因为 /srv/company-kb 的 owner 可能变成了容器用户,宿主机当前用户和 repo owner 不一致。
最小处理方式是:
git config --global --add safe.directory /srv/company-kb然后再试:
cd /srv/company-kb
git status这是 Git 的安全机制,不代表 repo 丢失或 Docker 挂载不一致。
不过这样, Git 不能操作的问题还是没有解决.
只能通过
cd /opt/kb-agent-stack
sudo docker compose exec opencode-web bash进入容器环境进行 add/commit 等.
14. 更新 AGENTS.md / README.md / START_HERE.md
引入 SFTPGo 后,项目说明文件也要更新。
否则同事会以为所有东西都从 OpenCode Web 进入,实际上现在有两个入口:
SFTPGo WebClient:上传 raw files
OpenCode Web:整理知识库草稿AGENTS.md 增加
## Raw File Ingestion
Raw files uploaded by business users are placed under:
- `inbox/uploaded-docs/`
These files are uploaded through SFTPGo WebClient, not through OpenCode Web.
When the user asks you to process uploaded files, first check the file path under:
- `inbox/uploaded-docs/`
Then create structured draft documents under:
- `review/pending/`
## Supported Input Materials
Preferred input materials:
- Markdown
- TXT
- CSV
- JSON
- YAML / YML
- page screenshots
- chart screenshots
- process screenshots
- de-identified business notes
- de-identified meeting notes
For office documents such as PDF, DOCX, XLSX, PPTX, scanned documents, image-based PDFs, zip files, or large attachments:
- Do not assume they can be directly parsed reliably.
- Ask the user to convert them to Markdown, TXT, CSV, JSON, YAML, or screenshots first.
- If the file is present but cannot be read as text, explain that preprocessing is required.
Uploaded files should be treated as raw materials, not approved knowledge.START_HERE.md 增加
# OpenCode Web 知识库工作台使用说明
这个工作台由两个入口组成:
```text
SFTPGo WebClient:上传原始文件
OpenCode Web:整理知识库草稿
```
上传文件请使用:
```text
http://SERVER_IP:8080/web/client
```
上传后的文件会进入:
```text
inbox/uploaded-docs/
```
整理知识库请使用:
```text
http://SERVER_IP:4096
```
第一次使用 OpenCode Web,请输入:
```text
/kb-start
```
所有新草稿请保存到:
```text
review/pending/
```
kb-start command 也需要更新
.opencode/commands/kb-start.md 应该提醒 agent 说明两个入口:
The message should include:
1. What this workspace is for
2. The two entry points: SFTPGo WebClient for upload, OpenCode Web for authoring
3. What kinds of documents the user can create
4. Where uploaded files are stored: `inbox/uploaded-docs/`
5. Where drafts should be saved: `review/pending/`
6. What the user must not upload or ask you to do
7. Three recommended example prompts
8. A reminder that uncertain information should go into Open Questions15. 输入文件范围
OpenCode Web 缺少完整文档解析管线,所以需要告诉同事“哪些文件适合直接使用”。
建议支持:
Markdown
TXT
CSV
JSON
YAML / YML
页面截图
图表截图
流程截图
已脱敏业务说明
已脱敏会议纪要暂不建议直接处理:
PDF
DOCX
XLSX
PPTX
扫描件
图片版 PDF
压缩包
大型附件
复杂多 sheet 表格这些文件最好先转换成:
Markdown
TXT
CSV
JSON
YAML
截图再交给 OpenCode 整理。
我测试上传了一个 .xlsx 文件, 可通过zip解压, 或python pandas等来读取, 但这不代表它总是能可靠解析 Excel。对这种文件,最好先导出成 CSV 或 Markdown。
16. 端到端验收
这次升级完成后,我的验收标准是:
[ ] OpenCode Web 可以访问
[ ] SFTPGo WebClient 可以访问
[ ] SFTPGo 上传文件能落到 /srv/company-kb/inbox/uploaded-docs
[ ] OpenCode 容器内能看到 /workspace/inbox/uploaded-docs
[ ] OpenCode Web 使用的是 /workspace project
[ ] /kb-start 能被发现
[ ] AGENTS.md 生效
[ ] skills 可以按任务被使用
[ ] OpenCode 能读取 uploaded-docs 中的文本文件
[ ] OpenCode 能生成 review/pending/*.md
[ ] git diff 能看到草稿变更
[ ] validate_kb.py 能跑建议先用 .md 或 .txt 做测试,不要一开始用 .xlsx。
例如创建测试文件:
cat > /srv/company-kb/inbox/uploaded-docs/test-note.md <<'EOF'
Sell-through means the ratio of sold units to ordered units.
The exact denominator needs business confirmation.
EOF然后在 OpenCode Web 里问:
请读取 inbox/uploaded-docs/test-note.md,并整理成 metric_definition 草稿,保存到 review/pending/test-sell-through.md。公式不确定处写 Needs confirmation。检查:
cd /srv/company-kb
git diff
ls -la review/pending
python3 scripts/validate_kb.py如果这一步成功,说明核心流程已经跑通。
17. 当前方案的边界
升级后,这套方案更适合内部 POC 和小范围试用:
内部 POC
小范围同事试用
知识库冷启动
业务文档草稿整理
FAQ / 指标定义 / 页面说明沉淀它仍然承担不了正式企业知识库系统的完整职责:
正式多人协同文档系统
复杂权限审批
生产级文档解析管线
大规模文件处理
多租户 SaaS 后台SFTPGo 和 Docker 主要解决:
文件上传入口
项目级隔离
运行边界仍然需要其他机制处理:
知识审核
内容准确性
RAG 切块质量
最终 Copilot 回答质量这些仍然要靠 Git review、validate 脚本、Dify/向量库处理和后续评测集。
18. 总结
上一篇的方案是:
OpenCode Web + Git repo + AGENTS.md + skills + permissions这次升级后变成:
Docker Compose
├── OpenCode Web
│ └── /workspace -> /srv/company-kb
│
└── SFTPGo WebClient
└── uploads -> /srv/company-kb/inbox/uploaded-docs我觉得这个版本更接近一个真正可用的内部 POC:
SFTPGo 解决 raw file upload
OpenCode Web 解决知识整理
Docker 解决项目级隔离
AGENTS.md / skills / commands 解决工作流约束
Git review 解决知识治理主要结论:
给同事使用的 OpenCode Web,应该作为被 Docker 限制在
/workspace内的项目级 agent 运行。