@@ -17,16 +17,24 @@
# --auth on|off|auto API key 认证(默认 auto:PG 档开、嵌入式关)
# --mock 演示模式(dev 常用)
# --plugins dir 插件目录(默认 <repo>/plugins)
# --model-base URL 启动后自动播种主模型配置(settings.models.chat.baseUrl)
# --model-key KEY 主模型 API Key(播种用;勿写入脚本/仓库)
# --model-name NAME 主模型名称
# --light-base/--light-key/--light-name 轻量模型(标题生成等;可选)
# --tavily-keys K1,K2 网络搜索密钥池(播种 tools.tavily.apiKeys)
# -- <剩余参数> 原样透传给 agent-system serve( escape hatch)
#
# 环境变量默认值:
# dev: 127.0.0.1:8788 数据 runtime/dev/data; SVC_DEV_ADDR/DATA/MOCK=1 可覆盖
# prod: 127.0.0.1:8787 数据 runtime/prod/data; SVC_PROD_ADDR/DATA/DSN/AUTH 可覆盖
#
# 一次性配置:把 SVC_MODEL_BASE/SVC_MODEL_KEY/SVC_MODEL_NAME 等写入 <repo>/.svc.env
#(已 gitignore),此后每次 start/deploy 自动播种,服务起来即可用。
#
# 示例:
# scripts/svc.sh dev --port 9000 --mock
# scripts/svc.sh prod --host 0.0.0.0 --dsn postgres://u:p@127.0.0.1:5432/as
# scripts/svc.sh dev deploy --addr 0.0.0.0:8788
# scripts/svc.sh dev --model-base https://api.xxx.com/v1 --model-key sk-xx --model-name glm-4.7
# make svc ENV=dev ARGS="--port 9000"
#
# 安全约束:
@@ -38,6 +46,10 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
RUNTIME = " $ROOT /runtime "
BIN = " $ROOT /bin/agent-system "
# 一次性配置文件(含密钥,已 gitignore):SVC_MODEL_* 等在此设好后每次启动自动生效。
# shellcheck disable=SC1090
[ -f " $ROOT /.svc.env " ] && . " $ROOT /.svc.env "
c_info( ) { printf '\033[1;34m[svc]\033[0m %s\n' " $* " ; }
c_ok( ) { printf '\033[1;32m[svc]\033[0m %s\n' " $* " ; }
c_warn( ) { printf '\033[1;33m[svc]\033[0m %s\n' " $* " ; }
@@ -50,6 +62,8 @@ usage() {
# ---- 命令行参数(覆盖层)----
CLI_ADDR = "" ; CLI_HOST = "" ; CLI_PORT = "" ; CLI_DATA = "" ; CLI_DSN = ""
CLI_AUTH = "" ; CLI_MOCK = 0; CLI_PLUGINS = "" ; CLI_EXTRA = "" ; CLI_LOGS_N = ""
CLI_MBASE = "" ; CLI_MKEY = "" ; CLI_MNAME = ""
CLI_LBASE = "" ; CLI_LKEY = "" ; CLI_LNAME = "" ; CLI_TAVILY = ""
need_value( ) { [ $# -ge 2 ] || { c_err " 参数 $1 需要值 " ; exit 2; } ; }
@@ -64,6 +78,13 @@ parse_args() {
--auth) need_value " $@ " ; CLI_AUTH = " $2 " ; shift 2 ; ;
--plugins) need_value " $@ " ; CLI_PLUGINS = " $2 " ; shift 2 ; ;
--mock) CLI_MOCK = 1; shift ; ;
--model-base) need_value " $@ " ; CLI_MBASE = " $2 " ; shift 2 ; ;
--model-key) need_value " $@ " ; CLI_MKEY = " $2 " ; shift 2 ; ;
--model-name) need_value " $@ " ; CLI_MNAME = " $2 " ; shift 2 ; ;
--light-base) need_value " $@ " ; CLI_LBASE = " $2 " ; shift 2 ; ;
--light-key) need_value " $@ " ; CLI_LKEY = " $2 " ; shift 2 ; ;
--light-name) need_value " $@ " ; CLI_LNAME = " $2 " ; shift 2 ; ;
--tavily-keys) need_value " $@ " ; CLI_TAVILY = " $2 " ; shift 2 ; ;
--) shift; CLI_EXTRA = " $* " ; break ; ;
-h| --help) usage; exit 0 ; ;
*) c_err " 未知参数: $1 " ; usage; exit 2 ; ;
@@ -117,7 +138,7 @@ pid_alive() {
local pid = " $1 "
[ -n " $pid " ] && [ -r " /proc/ $pid /cmdline " ] || return 1
local cmd
cmd = " $( tr '\0' ' ' < " /proc/ $pid /cmdline " 2>/dev/null) " || return 1
cmd = " $( { tr '\0' ' ' < " /proc/ $pid /cmdline " ; } 2>/dev/null ) " || return 1
case " $cmd " in
*agent-system*serve*) return 0 ; ;
*) return 1 ; ;
@@ -164,6 +185,48 @@ do_build() {
fi
}
# seed_settings:把 CLI/环境变量给出的模型与搜索配置写入 settings(幂等;
# 只写明确给出的字段;设置持久化在环境数据目录——播种一次后续启动无需再传)。
seed_settings( ) {
local host = " $1 " port = " $2 "
local cb = " ${ CLI_MBASE :- ${ SVC_MODEL_BASE :- } } " ck = " ${ CLI_MKEY :- ${ SVC_MODEL_KEY :- } } " cn = " ${ CLI_MNAME :- ${ SVC_MODEL_NAME :- } } "
local lb = " ${ CLI_LBASE :- ${ SVC_LIGHT_BASE :- } } " lk = " ${ CLI_LKEY :- ${ SVC_LIGHT_KEY :- } } " ln = " ${ CLI_LNAME :- ${ SVC_LIGHT_NAME :- } } "
local tk = " ${ CLI_TAVILY :- ${ SVC_TAVILY_KEYS :- } } "
[ -z " $cb $ck $cn $lb $lk $ln $tk " ] && return 0
command -v python3 >/dev/null 2>& 1 || { c_warn " [ $ENV_NAME ] 跳过配置播种:需要 python3 构造请求 " ; return 0; }
local payload
payload = " $( python3 - " $cb " " $ck " " $cn " " $lb " " $lk " " $ln " " $tk " <<'PY'
import json, sys
cb, ck, cn, lb, lk, ln, tk = sys.argv[1:8]
out = {}
def sub(base, key, name):
d = {}
if base: d["baseUrl"] = base
if key: d["apiKey"] = key
if name: d["model"] = name
return d
chat, light = sub(cb, ck, cn), sub(lb, lk, ln)
models = {}
if chat: models["chat"] = chat
if light: models["lightweight"] = light
if models: out["models"] = models
if tk: out["tools"] = {"tavily": {"apiKeys": tk}}
print(json.dumps(out))
PY
) "
local resp
resp = " $( curl -s -m 5 -X PUT " http:// $host : $port /api/settings/user " -H 'Content-Type: application/json' -d " $payload " ) "
if echo " $resp " | grep -q '"ok": *true' ; then
local did = ""
[ -n " $cb $ck $cn " ] && did = "主模型"
[ -n " $lb $lk $ln " ] && did = " ${ did : + $did 、 } 轻量模型 "
[ -n " $tk " ] && did = " ${ did : + $did 、 } Tavily "
c_ok " [ $ENV_NAME ] 已播种设置: $did (持久化于 $ENV_DATA ,后续启动无需再传) "
else
c_warn " [ $ENV_NAME ] 设置播种未成功: ${ resp :- <无响应> } (若开启了 API key 认证,需在设置页手动配置) "
fi
}
do_start( ) {
if pid_alive " $( read_pid) " ; then
c_warn " [ $ENV_NAME ] 已在运行 pid= $( read_pid) (如需换参数/新版本请用 deploy/restart) "
@@ -190,6 +253,7 @@ do_start() {
for _ in $( seq 1 100) ; do
if curl -s -o /dev/null -m 2 " http:// $host : $port / " 2>/dev/null; then
c_ok " [ $ENV_NAME ] 已启动 pid= $( cat " $ENV_PID " ) → http:// $host : $port (日志: $ENV_LOG ) "
seed_settings " $host " " $port "
return 0
fi
pid_alive " $( read_pid) " || { c_err " [ $ENV_NAME ] 进程启动后即退出,查看日志:tail -40 $ENV_LOG " ; exit 1; }