Janus:把 OpenCode 包装成统一的 Agent 网关
一个开源的 AI Agent 网关:统一协议、统一会话、统一模型与权限,但不重造 Agent 运行时。
我们面对的现实
2026 年的 coding agent 已经很多:OpenCode、Claude Code、Codex CLI、Gemini CLI……它们各自很强,但一旦你要把它们接进自己的系统,问题就来了:
- 每个 agent 只说自己的协议(Claude Code 说 Anthropic Messages,Codex 说 OpenAI Responses,OpenCode 是自有
/api/*); - 模型、鉴权、会话、权限、观测,全都散落在各个工具里;
- 想在它们之间切换、统一计费、统一审计,几乎要重写一遍 glue。
Janus 想解决的就是这一层。
Janus 是什么
一句话:
Agent 负责「怎么做」,Janus 负责「谁可以怎么用」。
Janus 是一个 OpenAI / Anthropic 兼容的网关 + 控制平面:把只有 /api/* 的 OpenCode server 包装成标准 /v1/*,让各类 OpenAI / Anthropic 客户端(Trae、CodeBuddy、Cursor、OpenAI SDK、LangChain…)直接可用;同时把会话、工具、权限、用量统一管起来。
它不重造 Agent runtime、Tool runtime、MCP runtime、Session runtime —— 这些交给 OpenCode 等现成的 agent,Janus 只做控制平面该做的事。
源码与安装
项目地址:https://github.com/qist/janus(MIT 许可)
方式一:下载预编译包(推荐)
到 Releases 下载对应架构的包(amd64 / arm64 / arm / 386):
1 | VERSION=v0.3.5 |
方式二:源码编译
1 | git clone https://github.com/qist/janus.git |
依赖:Go 1.23+;上游需要已安装 OpenCode(未装时 Janus 会在日志里提示安装命令)。
方式三:Docker / systemd
1 | # Docker(distroless 非 root 静态镜像) |
运行
1 | # 0. 先装 OpenCode(Janus 的上游 agent;未装时 Janus 会在日志里提示) |
OpenCode 不用你手动启动:Janus 启动时会自动发现已在跑的
opencode serve,没有就自己拉一个(随机端口 + 随机密码)。你只要把它装好即可 —— 所以也没有「填端口/密码」这一步。
客户端把 Base URL 指到 http://127.0.0.1:2810/v1、API Key 填 BRIDGE_API_KEY 即可,零改动;Anthropic 客户端则把 ANTHROPIC_BASE_URL 指到 http://127.0.0.1:2810。
已实现端点:/v1/models、/v1/chat/completions(流式+非流式)、/v1/completions、/v1/responses、/v1/messages(Anthropic)、/v1/usage、/v1/requests、/v1/settings、/ui、/metrics、/healthz。
三种执行模式(执行边界很清楚)
「工具在哪执行」由 BRIDGE_AGENT + BRIDGE_TOOL_CALLING 决定,按部署形态选一种:
| 模式 | 工具在哪执行 | 适合 |
|---|---|---|
native |
服务端(Janus 主机、会话目录) | 本机自用,链路最短 |
remote-tools |
客户端(走内置 MCP 工具桥) | 集中部署、代码在本地 |
none |
无工具(纯推理) | Chat / Review / 规划 |
remote-tools 里,MCP 只存在于 Janus ↔ agent 之间,对客户端始终是标准的 tool_calls / tool_use —— 客户端不用懂 MCP。
自用配置(可直接抄)
这是我们自己在用的一份 janus.env(已脱敏,路径请改成你自己的):
1 | # 监听与鉴权 |
切 native 模式:
BRIDGE_AGENT=build+BRIDGE_TOOL_CALLING=false。
切 none 模式:BRIDGE_AGENT=orchestrator+BRIDGE_TOOL_CALLING=false。OPENCODE_REUSE_EXTERNAL=false让 Janus 总是自己拉起 OpenCode —— 这是「自动注入 agent 配置」生效的前提。
一个叫 janus 的虚拟模型
痛点很具体:很多 IDE 用自定义模型名时没法设置思考档位(low/high/max),换模型还得改配置文件。
于是加了:
- 一个**虚拟模型
janus**:映射到/ui面板里选定的默认模型; - 面板「模型」页每行「设为 janus」;「思考档位」列是点选按钮组(点一下即设、当前高亮);
- 客户端/IDE 里模型名固定填
janus,换模型/换档位在面板点一下,不用改 env、不用改客户端。
关键是切换时机:面板改完,下一条请求就原地切换(Janus 调 POST /api/session/{id}/model),不重开会话、上下文保留——不需要等会话结束,也不用新开会话。
解析优先级:面板选择(存 DB) > BRIDGE_DEFAULT_MODEL > 上游默认。default / 留空 仍指向上游默认(旧语义不变);真实 provider/id 仍原样透传。两个都保留,互不干扰。
配置也不用手写了
跑 remote-tools 需要一个「禁用所有内置工具、只用客户端工具」的 agent。以前要手写 ~/.config/opencode/opencode.jsonc,问题是黑名单会随 OpenCode 版本改工具名而失效。
现在 Janus 拉起 OpenCode 时,通过 OPENCODE_CONFIG_CONTENT 自动注入自己生成的 agent 配置,而且是白名单:
1 | { |
不再手写、不怕版本改名、也不覆盖你自己的配置。
可观测:不用开官方 console
/v1/requests + /ui 提供逐条请求的缓存命中率、思考 token、耗时、费用,支持搜索/排序/分组汇总。面板拆成了 用量 / 最近请求 / 模型 / 运行 几个标签页。
Token 统计同时给出 OpenAI 的 prompt_tokens_details.cached_tokens 与 DeepSeek 风格的 prompt_cache_hit_tokens / prompt_cache_miss_tokens。
结语
如果你也在把各种 coding agent 往自己的系统里接,欢迎试试 Janus:它不替你造 agent,只把 agent 管好。
(本文对应版本:v0.3.5。)