13 KiB
ModelRouter / llmsproxy 交接文档
更新时间:2026-10-19
工作目录:/home/program/llmsproxy
当前分支:release/v2.0.x
1. 当前 Git 状态
最近提交:
c9f3453 fix(codearts): 识别 InferHub 未注册模型12bfd53 fix: 收口渠道源迁移与测试页合并25970a2 refactor(scheduler)!: 移除 priority 废弃字段 + 一通道一源 + discover 复用凭据
c9f3453 已推送到 origin/release/v2.0.x。
注意:当前工作树在最后一轮添加 provider 回归测试时出现了一个未完成且可能无法编译的测试编辑。最后一次工具报错:
internal/provider/provider_test.go:99: missing ',' in argument list
下一位 agent 接手后的第一步必须是:
cd /home/program/llmsproxy
git status --short
gofmt -w internal/provider/provider_test.go 2>&1 || true
go test -tags luajit ./internal/provider/ 2>&1
如果测试文件处于半编辑状态,先检查 TestProviderChatStreamNormalizesStopAfterToolCall,修正 Go 字符串转义或删除该未完成测试后再继续。不要直接部署当前工作树。
2. 生产服务状态
生产服务:llmsproxy.service
- 当前服务 active
- 监听:
0.0.0.0:8081 - 二进制已通过
./deploy.sh原子替换并重启 - 最近一次部署健康检查通过
- 当前生产插件 SHA256 前缀曾核对为:
1bf26cbb3abcb107 - 当前生产二进制在最近部署后已更新
不要把密钥写入交接记录。生产 admin key 保存在本机运维环境中,不应复制到聊天、文档或提交。
3. Channel 源当前状态
生产源已经从旧的“一账号一源”收口成“一渠道一源”:
channels-trae
channels-minimax
channels-lobsterai
channels-buddy
channels-codearts
channels-zcode
旧形态源已经清理:
channels-<provider>-<account_id>
此前旧源和新源并存,造成同一渠道同一模型出现多份,只能靠账号 hex 区分。
根因已修复:内核 list_sources 返回裸数组,但旧插件代码按 {sources = [...]} 信封读取,导致迁移清理循环永远为空。当前 channels.lua 已兼容:
- 裸数组
{sources = [...]}{json = {sources = [...]}}
相关代码:
internal/lua/plugins/channels.lua: syncProviderSource
internal/core/channels_legacy_source_cleanup_test.go
当前生产源列表已实测只有 6 个新形态源。
4. CodeArts 当前状态
已确认可用的部分
CodeArts 使用:
adapter = codearts
base_url = https://snap-access.cn-north-4.myhuaweicloud.com
CodeArts 的 chat 请求需要完整 AK/SK/security token 凭据,由插件适配器签名,不是裸 Bearer token。
真实流式工具调用测试已经成功:
请求形状:
{
"model": "channels-codearts:openpangu-2.0-flash",
"messages": [{"role": "user", "content": "Use the weather tool for Beijing."}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}],
"tool_choice": "auto",
"stream": true,
"max_tokens": 64
}
结果:
- HTTP 200
Content-Type: text/event-stream- 返回结构化
tool_calls - 函数名
get_weather - 参数最终为
{"city":"Beijing"} finish_reason = tool_calls
因此 CodeArts 的流式工具调用链路当前是通的。
CodeArts 模型刷新
生产调用:
POST /api/plugins/http/channels/model/refresh
{"platform":"codearts"}
实测返回:
{
"ok": true,
"results": [
{"platform": "codearts", "ok": true, "count": 11}
]
}
CodeArts 模型目录来自两个签名端点并合并:
opengw.developer.huaweicloud.com/api/v1/gateway/configresult.models
snap-access.cn-north-4.myhuaweicloud.com/v1/model/builtinbuiltinModels
相关解析:
internal/lua/plugins/channels.lua: parseRemoteModels
internal/lua/plugins/channels.lua: refreshRemoteModels
internal/core/channels_codearts_catalog_test.go
已确认失效并禁用的 CodeArts 模型
下面 4 个模型曾收到明确的上游 404:
CodeArts-Pangu
deepseek-v4-flash-0731
deepseek-v4-pro-0813
glm-5.3-flash
生产上已通过 channels/model/set_disabled 禁用。它们仍可能在 model/list 中出现,但 disabled=true,不会作为可用模型路由。
新增的死模型判据:
model is not registered
对应提交:c9f3453。
注意:当前插件的 dead-model 机制只在收到真实请求失败后记录模型;刷新目录不会自动根据“远端目录没有该模型”删除模型,这是刻意设计,避免误删远端目录不完整的平台模型。
CodeArts 当前仍有一些模型返回 429/TPM 限流,例如:
deepseek-v4-flash
deepseek-v4.1-flash
429 不是模型失效,不能禁用。
5. 其他 Channel 实测结果
Trae
真实流式 + tools 请求:
channels-trae:DeepSeek-V4-Flash
结果:
- HTTP 200
- SSE 正常返回
- 结构化 tool call 返回
- 但上游最后的结束原因可能是
stop,即使前面已经出现 tool-call fragments
这会让 Agent 把工具调用误判成普通文本完成。
当前准备中的修复在统一 provider 流式层:
internal/provider/provider.go
逻辑是:只要本次流出现真实 tool-call 片段,后续 FinishReason == "stop" 就归一成 tool_calls。
另外,Trae 的非流式接口偶尔返回 SSE。当前 trae.lua 对非流式 SSE 只取最后一条 data,不能完整合并多条工具调用/推理片段。这是后续仍需处理的协议问题,但不能用非流式手工请求结果推断 Pi 的真实请求模式。
Buddy
真实流式 + tools 请求:
channels-buddy:glm-5.3-flash
结果:
- HTTP 200
- SSE 正常返回
- tool-call 参数分片可见
- 最终有
finish_reason = tool_calls - 但某些上游 chunk 的
tool_calls可能是空对象{}
空对象不是合法的 OpenAI tool-call 数组,部分 Agent 客户端会拒绝。
当前准备中的修复在:
internal/lua/adapters/buddy.lua
只在 type(delta.tool_calls) == "table" and #delta.tool_calls > 0 时输出 tool_calls,避免 Lua 空表被编码为 {}。
Buddy 的非流式错误:
11101: Non-stream chat request is currently not supported
之前出现的该错误来自手工 curl 测试中显式设置 stream:false,不能归因到 Pi。真实 stream:true + tools 已经证明 Buddy 流式工具调用可以工作。
MiniMax
生产日志反复出现:
adapter "anthropic": status=401 body={"error":"invalid access token"}
provider channels-minimax: api error 401
这是凭据失效问题,不是 tools 形状问题。
当前源:
channels-minimax
adapter = anthropic
endpoint = /mavis/api/v1/llm/v1/messages
需要用户重新登录/提供有效凭据。不要擅自刷新一次性 refresh token,之前已经发生过 refresh token 被消耗后无法再次使用的事故。
6. 当前未提交的代码改动
最后一轮已经改动但尚未完成提交:
internal/provider/provider.go
internal/lua/adapters/trae.lua
internal/lua/adapters/buddy.lua
internal/provider/provider_test.go # 可能有半编辑、需先修复
已完成的意图:
- provider 流式层记录
sawToolCalls - 看到真实 tool-call 后,把后续
stop归一为tool_calls - Trae 不输出空工具调用表
- Buddy 不输出空工具调用表
- provider 回归测试模拟“tool fragment + stop”场景
但 provider 测试最后一次编辑工具报错:
internal/provider/provider_test.go:99: missing ',' in argument list
因此必须先修测试文件,再提交。
7. 推荐接手顺序
第一步:修复工作树
cd /home/program/llmsproxy
git status --short
sed -n '1,150p' internal/provider/provider_test.go
gofmt -w internal/provider/provider_test.go 2>&1 || true
go test -tags luajit ./internal/provider/ 2>&1
若测试函数字符串转义难以修复,先删除半成品测试,再重新用 raw string 写测试。
第二步:跑定向验证
luac -p internal/lua/adapters/trae.lua
luac -p internal/lua/adapters/buddy.lua
go test -tags luajit ./internal/provider/
go test -tags luajit ./internal/lua/ -run 'Adapter|Buddy|Trae|Stream'
第三步:构建并部署临时验证版
修复确认后:
go build ./...
./deploy.sh
部署前确认:
sha256sum internal/lua/plugins/channels.lua
sha256sum /etc/llmsproxy/plugins/channels.lua
systemctl is-active llmsproxy
第四步:真实流式回归
不要用 stream:false 测试流式问题。使用:
KEY='<从本机安全环境读取,不写入文档>'
TOOL='{"type":"function","function":{"name":"get_weather","description":"Get weather","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}'
curl --no-buffer --max-time 90 \
-H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
-d "{\"model\":\"channels-codearts:openpangu-2.0-flash\",\"messages\":[{\"role\":\"user\",\"content\":\"Use the weather tool for Beijing.\"}],\"tools\":[$TOOL],\"tool_choice\":\"auto\",\"stream\":true,\"max_tokens\":64}" \
http://127.0.0.1:8081/v1/chat/completions
分别将 model 替换为:
channels-codearts:openpangu-2.0-flash
channels-trae:DeepSeek-V4-Flash
channels-buddy:glm-5.3-flash
验收:
- HTTP 200
Content-Type: text/event-stream- 不能出现
tool_calls: {} - 有 tool-call fragments 时最终必须是
finish_reason: tool_calls - CodeArts 当前应继续返回结构化工具调用
第五步:CodeArts 刷新验收
curl -sS -X POST \
-H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
-d '{"platform":"codearts"}' \
http://127.0.0.1:8081/api/plugins/http/channels/model/refresh
预期:
{"ok":true,"results":[{"platform":"codearts","ok":true,"count":11}]}
再检查:
curl -sS -X POST \
-H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
-d '{"platform":"codearts"}' \
http://127.0.0.1:8081/api/plugins/http/channels/model/list
预期:远端目录 11 个 + 兜底补位,已确认 404 的 4 个仍保持 disabled=true。
8. 发布/安装包状态
目前没有完成“全部安装包”发布闭环。
已经发生的事情:
- 核心包构建成功,但脚本实际使用了
git describe,产物版本类似:2.0.40~4-gc9f3453 - Linux GUI 包构建成功,版本为
1.9.7 - Windows 主机 Wine 构建失败,生成了一个 264KB 的坏
ModelRouter Setup 1.9.7.exe,绝对不能发布 - Docker Windows 构建也失败在拉取 Docker Hub 基础镜像
golang:1.25网络超时 - apt 无法找到
wine32:i386 - 旧的 1.9.5/1.9.6 Windows 包是历史产物,不能作为当前版本
不要把旧 Windows exe 当作新包发布。
仓库已有 Docker 方案:
cmd/gui/scripts/dist-win-docker.sh
cmd/gui/docker/win-builder/Dockerfile
但当前 Docker Hub 网络不可用。若要继续做 Windows 包:
- 在可访问 Docker Hub 的构建机/CI 执行 Docker 方案;或
- 提供包含 Wine32/Wine64 的完整构建环境;或
- 暂时只发布 Linux/core 包,并明确说明 Windows 包未完成。
版本脚本注意:
-
核心包脚本使用位置参数:
./packaging/core-dist.sh 2.0.41不是
VERSION=2.0.41 ./packaging/core-dist.sh。 -
GUI 版本来自
cmd/gui/package.json,环境变量VERSION不会自动修改 Electron 产品版本。 -
清理旧产物后再打包,并在全部包完成后统一计算
SHA256SUMS。
9. 参考插件状态
用户要求按:
https://github.com/Ebony-Vinyl/dsh-our-free-model
逐厂商对照参考插件。
当前本地路径:
/tmp/pi-github-repos/Ebony-Vinyl/dsh-our-free-model
但该目录当前不是有效可读源码副本:
vendor/channel-pack/src下面只有空目录;.git没有有效HEAD/refs;- 无法从本地 Git 对象恢复源码;
- 本地也没有
buddy.ts、trae.ts、codearts.ts等文件。
因此不能声称当前适配器是逐行照参考插件移植的。若要继续按用户要求完成,必须先重新 clone/恢复该 GitHub 仓库源码,确认以下文件实际存在后再对照:
vendor/channel-pack/src/trae.ts
vendor/channel-pack/src/buddy.ts
vendor/channel-pack/src/codearts.ts
vendor/channel-pack/src/*adapter*
vendor/channel-pack/src/*model*
当前仓库代码只能作为临时协议修复基础,不能代替参考插件源码。
10. 关键结论
- Pi 是否发送流式请求,历史日志没有保存入站
stream/tools字段,不能靠旧日志判断。 - 本次真实
stream:true + tools测试证明 ModelRouter 流式路径能工作:- CodeArts:通过;
- Trae:通过但结束原因需归一;
- Buddy:通过但需过滤空
{}; - MiniMax:凭据 401,独立问题。
- 不要再用
stream:false的手工请求推断 Pi 的问题。 - CodeArts 刷新接口当前真实返回
ok=true,count=11,刷新链路不是当前阻塞点。 - 当前最紧急的代码状态是修复
provider_test.go的半编辑,然后验证未提交的统一流式修复。 - 未经测试、未重新构建、未重新部署,不要继续改生产账号或刷新一次性凭据。