Skip to content

Latest commit

 

History

History
396 lines (296 loc) · 10.4 KB

File metadata and controls

396 lines (296 loc) · 10.4 KB

Opencode API 服务 — 完整部署指南

将本地 opencode 封装为 完全 OpenAI 兼容 API,支持流式、非流式、工具调用(tool calling)。 智能体拥有完整能力:读写文件、执行命令、调用工具等。


架构

Reeden / Cursor / NextChat / 任何 OpenAI 客户端
        │  POST /v1/chat/completions (OpenAI 格式)
        │  stream: true/false, tools: [...]
        ▼
opencode-session-proxy  (127.0.0.1:18081)   ← 本仓库的核心
        │  创建 session → 发消息 → 监听 SSE 事件
        ▼
opencode serve         (127.0.0.1:4096)    ← opencode 原生 API
        │  完整智能体引擎

设计要点:

  • 不用 opencode run(一次性问答,无 agent 能力)
  • /session API + /global/event SSE 流 → 智能体拥有完整能力
  • 工具调用:拦截 OpenAI tools → 注入系统提示告诉 AI 用 [TOOL_CALL: name] {args} [/TOOL_CALL] 格式
  • AI 响应中解析该格式 → 转换为 OpenAI tool_calls 格式返回
  • 无自动重试:信任模型判断,未检测到 [TOOL_CALL:] 时视为有效文本响应直接结束。避免因误判导致的无限循环和重复任务提交。
  • 防泄漏过滤:内置三层防御机制防止系统指令泄漏到输出中(pre-prompt 提示、流式前缀检测、响应后处理)。
  • Delta 超时检测:每 5s 检查一次,内容 30s 无增量则主动结束,替代固定超时。

前置条件

组件 版本要求 说明
mise 任意 包管理器
opencode v1.14+ mise install opencode@1.14.46
Node.js v18+ 运行 proxy 脚本(可用 mise install node
systemd 有 user mode Linux 发行版自带

部署步骤

第一步:opencode serve(端口 4096)

这是基础服务,opencode 的原生 API 服务器。

1.1 安装 opencode

mise install opencode@1.14.46
mise use -g opencode@1.14.46
opencode --version  # 确认安装

1.2 首次运行(初始化必要文件)

opencode serve --hostname 127.0.0.1 --port 4096
# Ctrl+C 终止,确认无报错即可

首次运行会在 ~/.opencode/ 下创建配置目录。 如果遇到 btca CLI not found 可忽略(不影响的源码搜索功能)。

1.3 创建 systemd 服务

mkdir -p ~/.config/systemd/user

写入文件 ~/.config/systemd/user/opencode-api.service

[Unit]
Description=Opencode API Server
After=network.target

[Service]
Type=simple
ExecStart=%h/.local/share/mise/installs/opencode/1.14.46/opencode serve --hostname 127.0.0.1 --port 4096
WorkingDirectory=%h
Restart=on-failure
RestartSec=5
Environment=HOME=%h

[Install]
WantedBy=default.target

%h 是 systemd 的 home 目录变量,会自动替换。

1.4 启用并启动

# 重新加载 systemd
systemctl --user daemon-reload

# 启动服务
systemctl --user start opencode-api.service

# 查看状态
systemctl --user status opencode-api.service

# 设为开机自启
systemctl --user enable opencode-api.service

# 如果开机不自动启动(用户未登录时),执行:
sudo loginctl enable-linger $(whoami)

1.5 验证

# 健康检查
curl -s http://127.0.0.1:4096/health

# 应该返回类似:{"status":"ok"}

第二步:session proxy(端口 18081)

这是 OpenAI 兼容适配层,直接调用 opencode 的 session API。

2.1 安装 Node.js

mise install node@latest
mise use -g node@latest
node --version  # 确认 v18+

2.2 部署 proxy

核心文件是仓库里的 session-proxy.js(OpenAI 兼容代理)。

# 复制到运行目录
cp session-proxy.js ~/.opencode-cli-proxy/bin/opencode-session-proxy.js

# 或者直接下载最新版(适合远程部署)
curl -sL https://raw.githubusercontent.com/brucevon/opencode-api-deploy/main/session-proxy.js \
  -o ~/.opencode-cli-proxy/bin/opencode-session-proxy.js

2.3 配置(环境变量)

所有配置通过环境变量设置,无需修改代码:

变量 默认值 说明
PROXY_PORT 18081 proxy 监听端口
OPCODE_PORT 4096 opencode serve 端口
OPCODE_HOST 127.0.0.1 opencode serve 地址
API_KEY sk-gw-demo 认证密钥
MODELS opencode/big-pickle,... 逗号分隔的模型列表

2.4 创建 systemd 服务

写入文件 ~/.config/systemd/user/opencode-session-proxy.service

[Unit]
Description=Opencode Session Proxy - Full agent via OpenAI API
After=network.target opencode-api.service
Wants=opencode-api.service

[Service]
Type=simple
ExecStart=%h/.local/share/mise/installs/node/latest/bin/node %h/.opencode-cli-proxy/bin/opencode-session-proxy.js
WorkingDirectory=%h
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target

2.5 启用并启动

systemctl --user daemon-reload
systemctl --user start opencode-session-proxy.service
systemctl --user enable opencode-session-proxy.service
systemctl --user status opencode-session-proxy.service

第三步:检查开机自启

# 如果重启后服务不启动,执行:
sudo loginctl enable-linger $(whoami)

验证

确保两个服务都在运行后:

3.1 健康检查

# opencode 原生 API
curl -s http://127.0.0.1:4096/health

# session proxy
curl -s http://127.0.0.1:18081/v1/models \
  -H "Authorization: Bearer sk-gw-demo"

3.2 非流式聊天

curl -s --max-time 180 -X POST http://127.0.0.1:18081/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-gw-demo" \
  -d '{
    "model": "opencode/big-pickle",
    "messages": [{"role": "user", "content": "创建一个 /tmp/proxy-test.txt 文件,写入 hello world"}],
    "stream": false
  }'

智能体应该执行 write 工具创建文件,然后返回结果。 首次请求模型需要热加载,可能耗时 60s+,后续请求正常。

3.3 流式聊天

curl -N --max-time 180 -X POST http://127.0.0.1:18081/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-gw-demo" \
  -d '{
    "model": "opencode/big-pickle",
    "messages": [{"role": "user", "content": "从 1 数到 5"}],
    "stream": true
  }'

3.4 工具调用测试

# 非流式 + tools
curl -s --max-time 180 -X POST http://127.0.0.1:18081/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-gw-demo" \
  -d '{
    "model": "opencode/big-pickle",
    "messages": [{"role": "user", "content": "Search for books about artificial intelligence"}],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "search_books",
          "description": "Search books by query",
          "parameters": {
            "type": "object",
            "properties": {"query": {"type": "string"}},
            "required": ["query"]
          }
        }
      }
    ],
    "stream": false
  }'
# 应返回 finish_reason: "tool_calls",含 tool_calls 数组
# 流式 + tools
curl -N --max-time 180 -X POST http://127.0.0.1:18081/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-gw-demo" \
  -d '{
    "model": "opencode/big-pickle",
    "messages": [{"role": "user", "content": "Search for books about AI"}],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "search_books",
          "description": "Search books by query",
          "parameters": {
            "type": "object",
            "properties": {"query": {"type": "string"}},
            "required": ["query"]
          }
        }
      }
    ],
    "stream": true
  }'
# 应输出 SSE delta 事件:
# 1. delta: {role: "assistant"}
# 2. delta: {tool_calls: [{...}]}
# 3. delta: {}, finish_reason: "tool_calls"
# 4. [DONE]


管理命令

# 查看状态
systemctl --user status opencode-api.service opencode-session-proxy.service

# 查看日志
journalctl --user -u opencode-session-proxy.service -f

# 重启
systemctl --user restart opencode-session-proxy.service

# 停止
systemctl --user stop opencode-session-proxy.service

# 查看 N 条最近日志
journalctl --user -u opencode-session-proxy.service --no-pager -n 50

故障排查

服务起不来

# 先看日志
journalctl --user -u opencode-session-proxy.service --no-pager -n 50

# 常见原因:
# - node 路径不对 → which node 确认路径,更新 ExecStart
# - opencode-api 没启动 → systemctl --user start opencode-api.service
# - 端口被占用 → netstat -tlnp | grep 18081

请求返回 401

API Key 不匹配。检查 session-proxy.js 中的 API_KEY 和请求头的 Authorization

返回空内容(首次请求)

模型冷启动需要时间。重试一次即可。或者先发一个简单的 warm-up 请求:

curl -s --max-time 180 -X POST http://127.0.0.1:18081/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-gw-demo" \
  -d '{"model":"opencode/big-pickle","messages":[{"role":"user","content":"hi"}],"stream":false}'

工具调用不生效(返回文本而非 tool_calls)

opencode/big-pickle 是 agent 模型,约 40% 概率会忽略 [TOOL_CALL:] 指令,直接用内置工具在服务器执行。这种情况下响应中不含 tool_calls,客户端不会执行任何工具。

Proxy 内置了自动重试机制:检测到需要 tools 但模型没输出时,自动发送修正消息重试(同一 session,最多 3 次)。通常第二次即可正确输出 [TOOL_CALL:] 格式。

如果仍有问题,尝试:

  1. 重新发送请求(重试次数重置)
  2. 用非流式模式(stream: false),成功率更高

跨机器访问不工作

确认:

  1. proxy 监听地址改为 0.0.0.0(在 session-proxy.js 中改 PROXY_HOST = '0.0.0.0'
  2. 防火墙放行 18081 端口
  3. 确保 API Key 匹配

自定义

修改端口

编辑 session-proxy.js 开头的 PROXY_PORT 变量,然后重启服务:

systemctl --user restart opencode-session-proxy.service

修改 API Key

编辑 session-proxy.js 开头的 API_KEY 变量,重启服务。

添加更多模型

编辑 session-proxy.js 开头的 MODELS 数组,添加模型 ID。需要确保 opencode 配置中已有该模型(opencode config)。