modlink-agent —— 模联平台的 Agent 工具包
把模联(ModLink)的模型能力封装成 CLI 命令与 MCP 工具,供 AI Agent 调用。
平台侧接口见 API 文档,本包是它的 Agent 友好封装。
⚠️ 安全约束:不提供对话模型
本包刻意不封装 LLM 对话模型(qwen3-coder-next),CLI 也没有 chat 子命令。
平台十余个模型里,只有对话模型同时具备两个特性:
- 接受任意提示词 —— 其余模型都是「输入固定格式数据、输出固定格式结果」
- 能调用工具 —— 可通过
tools/tool_choice组合出调用链
把它做成 Agent 可调用的工具,等于把 Agent 的控制面交给不可信输入。提示词注入的后果是任意的:
- 诱导 Agent 读取不该读的文件、执行不该执行的命令
- 通过
tools组合出「看起来像合法业务调用」的越权链 - 借 Agent 的身份绕过人类已经设好的权限边界
这不是能力缺失,是刻意的取舍。
- 需要使用对话模型的用户:仍可直接调平台的
/v1/chat/completions+ 自建 API Key - Agent 的规划与生成能力:应交给宿主自带的主模型,不要二次调用本平台的对话模型
该约束由单元测试与端到端验证双重钉死(hasattr 断言 + 子命令集检查),
防止日后有人「顺手加回来」。
安装
pip install -e . # 只用 CLI
pip install -e ".[mcp]" # 需要 MCP Server
依赖只有 requests 一个;MCP SDK 是可选项,只用 CLI 不需要装。
配置 API Key
API Key 在模联用户控制台 → API Key 页创建。 支持四种来源,优先级从上到下:
| 优先级 | 来源 | 说明 |
|---|---|---|
| 1 | 环境变量 MODLINK_API_KEY |
推荐。不进 shell history 与进程列表 |
| 2 | 配置文件 ~/.config/modlink-agent/config.json 的 apiKey |
免重复输入 |
| 3 | MCP 客户端配置的 env 段 |
见下方「MCP 接入」 |
| 4 | 交互式输入(仅 CLI 且在 TTY 下) | 首次试用 |
优先级不可绕过:环境变量存在时会忽略明文。 否则「先设了环境变量、后又改了面板配置」会静默用错一把 Key, 表现为「明明配了 A 却按 B 的额度扣费」,极难排查。
为什么不用命令行传 Key
--api-key ml_live_xxx 会进 shell history,也会被 ps aux 看到。
环境变量在同一台机器上通过 /proc/PID/environ 也能被同用户读到,
但不会落进 history 与审计日志——这是 CLI 工具的通行取舍。
--key 参数仍然保留(供程序化调用),但优先级低于环境变量。
全部环境变量
| 变量 | 必填 | 默认 | 说明 |
|---|---|---|---|
MODLINK_API_KEY |
✅ | — | API Key |
MODLINK_BASE_URL |
https://asr.syncmeet.tech:9443 |
网关地址 | |
MODLINK_WORK_DIR |
./modlink-out |
音频/图片落盘目录 | |
MODLINK_TIMEOUT |
600 |
单请求超时(秒) | |
MODLINK_ASYNC_THRESHOLD |
15 |
超过该秒数视为长任务,转异步轮询 |
模型白名单自动生效
在用户端创建 Key 时若设了「模型白名单」,本包无需任何配置即可正确受限:
# 用只授权向量的 Key
export MODLINK_API_KEY=ml_live_xxx
modlink models
# 只列出 qwen3-embedding —— 平台侧 /v1/models 已按白名单过滤
modlink translate "你好" --to 英语
# 当前 API Key 无权调用模型 hymt2-translate。该 Key 的模型白名单为:qwen3-embedding。
# 如需调用,请在「API Key」页修改白名单或新建 Key。
CLI 用法
modlink models # 列出当前 Key 可调用的模型
modlink health # 检查平台可达性
modlink transcribe a.wav --model funasr --diarization
modlink synthesize "欢迎使用模联" --model cosyvoice
modlink translate "你好" --to 英语
modlink embed "模联平台" --dimensions 1024
modlink image photo.jpg --task upscale
modlink generate "一只橘猫" --width 1024 --height 1024
没有
chat子命令 —— 见上方「安全约束」。
所有子命令支持 --json 输出结构化结果,便于脚本与 Agent 解析:
modlink models --json | jq '.data[].id'
图像任务对应关系
--task |
默认模型 | 额外必填 |
|---|---|---|
remove_background |
birefnet-matting |
— |
erase |
lama-inpaint |
--mask |
upscale |
realesrgan-upscale |
— |
face_restore |
codeformer-restore |
— |
face_swap |
inswapper-face-swap |
--source-image |
作为 Python 库
from modlink_agent import ModLinkClient
client = ModLinkClient() # 自动读环境变量
# 文本类直接返回结果
print(client.translate("你好", target_lang="英语"))
print(client.embed(["文档A", "文档B"], dimensions=1024))
# 二进制类返回**文件路径**,不是内容
audio = client.synthesize("欢迎使用模联")
print(audio.path) # ./modlink-out/tts-20261006-200547-xxx.wav
print(audio.describe()) # 一句话摘要(不含任何二进制内容)
客户端没有
chat/chat_text/stream_chat方法 —— 见上方「安全约束」。
三个为 Agent 做的关键设计
① 二进制不进上下文
一张 1024×1024 图转 base64 约 1.4MB token,会直接撑爆 Agent 上下文。 本包一律落盘后只返回绝对路径:
result = client.generate_image("一只猫")
print(result.path, result.size_bytes) # 路径 + 字节数,不含内容
② 429 自动退避
图像模型同卡互斥(平台文档明写「必须串行调用」),Agent 天生并发,一并发就吃 429。 若把 429 原样抛出,Agent 只会反复重试并再次 429,形成死循环。
本包读 Retry-After 头做指数退避,重试耗尽后返回可执行的提示:
模型互斥或触发限流(429),重试 4 次仍失败。
平台说明:图像生成类模型**同卡互斥,必须串行调用**。
请改为逐个调用(等上一个返回后再发下一个),或稍后再试。
③ 长任务不超时
- ASR:长音频自动走
/v1/asr/tasks异步接口,内部轮询到完成 (按音频大小启发式判断,调用方无需决策) - 图像:平台无异步接口,用长超时 + 返回值带耗时秒数
实测真机耗时(供参考,用于设置 MCP 客户端超时):
| 操作 | 耗时 |
|---|---|
| 翻译(2 条批量) | 0.16s |
| 向量化(2 条 / 256 维) | 0.09s |
| 图像超分(64×64) | 0.15s |
| 语音合成(1 句 → 86KB WAV) | 1.38s |
| 语音转写(1 句) | 0.29s |
图像生成(1024×1024,20B 模型)实测需数十秒到数分钟, 且同卡互斥(并发会 429)——MCP 客户端应给足超时并串行调用。 本包已内置 429 退避,但客户端超时也要相应放宽。
关于函数调用(工具调用)
平台侧的 /v1/chat/completions 完整支持 tools / tool_choice
与多轮 tool_calls 回传(平台只做透传,不执行工具——模型只负责
「提出调用请求」,由调用方执行后把结果作为 role=tool 消息回传,
漏掉 tool_call_id 会让模型重复发起同一次调用)。
但本包不封装对话模型(见上方「安全约束」),因此 Agent 侧 不会拿到这个入口——函数调用能力请直接在平台侧使用。
MCP 接入
配置
command 指向装了 MCP SDK 的那个解释器 —— 若报 No module named mcp,
说明该解释器缺依赖,用装了 SDK 的那个(如 …/venvs/mcp-agent/bin/python)。
方式一:Key 走环境变量(推荐)
{
"mcpServers": {
"modlink": {
"command": "python",
"args": ["-m", "modlink_agent.mcp_server"],
"env": {
"MODLINK_API_KEY": "ml_live_xxxxxxxx"
}
}
}
}
env 段写死的值就是「配置文件/显式传入」层,优先级低于机器上真实的环境变量
(见上方 Key 表格第 1 行)。也就是说:面板里填了明文,但进程环境变量里
存在 MODLINK_API_KEY 时,后者胜出。这样 Key 可以从 CI secret 或
~/.bashrc 统一注入,不必落到面板配置里。
方式二:环境变量已在 shell 里
{
"mcpServers": {
"modlink": {
"command": "python",
"args": ["-m", "modlink_agent.mcp_server"],
"env": {}
}
}
}
工具清单(7 个)
按「族」暴露,不按模型拆成一堆工具 —— 一模型一工具会让 Agent 在 20+ 个 名字里纠结选择,且模型下线后工具名就变成死引用。
| 工具 | 作用 | 覆盖模型 |
|---|---|---|
modlink_list_models |
列出当前 Key 可调模型 | 全部(按白名单过滤) |
modlink_transcribe |
语音转写 | funasr / sensevoice / paraformer-bilingual / zipformer-bilingual |
modlink_synthesize |
语音合成 | cosyvoice / indextts |
modlink_translate |
文本翻译 | hymt2-translate |
modlink_embed |
文本向量化 | qwen3-embedding |
modlink_image_process |
图像处理 | 抠图 / 消除 / 超分 / 人脸修复 / 换脸 |
modlink_image_generate |
图像生成 | flux2-generate / qwen-image-2.1 |
不包含对话工具(modlink_chat 不存在)——与 CLI 保持一致的安全边界。
客户端可用 modlink_list_models 自查可调范围,但其中不会出现对话模型。
Server Instructions
Server 带一段面向 Agent 的说明,覆盖三类「模型自身不会说」的知识:
- 二进制结果返回的是文件路径而非内容,需要 Agent 再用文件工具读取
- 图像生成/处理同卡互斥,并发会 429
- 图像生成耗时长(1024×1024 数十秒到数分钟),需要给足超时
modlink_list_models 的存在是必要的:不调它,Agent 无从知道
「这个 Key 到底能用什么」,只能靠猜或反复试错吃 403。
错误处理
| 异常 | 触发条件 | 提示要点 |
|---|---|---|
AuthenticationError |
401 | Key 无效/吊销/过期,指向控制台检查 |
ForbiddenError |
403 | 模型白名单未授权,提示去改白名单 |
InsufficientCredits |
402 | 积分不足,指向充值页 |
RateLimitError |
429 | 模型互斥,提示改串行 |
ModelNotFound |
404 / 503 | 模型标识错或未部署 |
UpstreamError |
5xx | 平台或引擎异常 |
错误文案都是给 Agent 读的,每条都包含下一步该做什么—— Agent 拿到「HTTP 403」只会反复重试同一个错误调用。
测试
python tests/test_client_local.py # 32 项:起本地假 HTTP 服务,不连生产
python tests/test_mcp_local.py # 44 项:含真实 stdio 握手
test_mcp_local.py 会真的起一个 python -m modlink_agent.mcp_server
子进程,走完整 JSON-RPC 握手并 list_tools —— 因为 stdio 传输下
stdout 是协议通道,任何一处 print 都会破坏 JSON-RPC 帧,
而这类问题不真起进程就测不出来。
真机验证覆盖 7 个族各调一次。
Metadata
Release files for modlink-agent 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| modlink_agent-1.1.0.tar.gz | 50.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| modlink_agent-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 89.4 kB
Release files / modlink_agent-1.1.0.tar.gz
| Download URL | modlink_agent-1.1.0.tar.gz |
|---|---|
| Size | 50.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac09eeabb48b052f774ac7efe0b4f7103c404f5394016f7f1284a16b5e8cf5f3
|
|
BLAKE2b-256 checksum How to use checksums |
f7013fb823fd04359d6f0d3d28c47568e7fc219c6223b41dd6840bf9244b0117
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.8
|
Release files / modlink_agent-1.1.0-py3-none-any.whl
| Download URL | modlink_agent-1.1.0-py3-none-any.whl |
|---|---|
| Size | 39.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0cd94bd4e2ef6d83c6331168049e326c2d5c92372714e3274066e1be763245d3
|
|
BLAKE2b-256 checksum How to use checksums |
9387242bb0b7dccd15c130371b8cf5b1913fb3d773d0a35614f31edba6c6d699
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.8
|