refactor(sub_agent): 子智能体模型配置外置化,对齐 custom_models.json 设计

- config/sub_agent.py: 新增 resolve_sub_agent_models_config() 和 SUB_AGENT_MODELS_CONFIG_FILE,回退链:外置 → 源码种子 → easyagent/ 旧位置 → .example 兜底
- modules/sub_agent_manager.py: 子进程启动时传递 --config-file 参数
- easyagent/src/config.js: ensureConfig() 支持可选 customPath 参数
- easyagent/src/batch/index.js: 新增 --config-file CLI 参数
- config/sub_agent_models.json.example: 新增种子模板
- easyagent/models.json: 更新默认模型
This commit is contained in:
JOJO 2026-06-10 01:44:39 +08:00
parent 6255efc594
commit 4ba15555b7
6 changed files with 68 additions and 9 deletions

View File

@ -1,8 +1,15 @@
"""子智能体相关配置。"""
import os
from pathlib import Path
from .paths import _resolve_repo_path, DATA_DIR, DEFAULT_PROJECT_PATH
from .paths import (
_resolve_repo_path,
_REPO_ROOT,
DATA_DIR,
DEFAULT_PROJECT_PATH,
resolve_deploy_config,
)
# 子智能体服务
SUB_AGENT_SERVICE_BASE_URL = os.environ.get("SUB_AGENT_SERVICE_URL", "http://127.0.0.1:8092")
@ -17,6 +24,32 @@ SUB_AGENT_STATE_FILE = _resolve_repo_path(os.environ.get("SUB_AGENT_STATE_FILE",
SUB_AGENT_PROJECT_RESULTS_DIR = _resolve_repo_path(os.environ.get("SUB_AGENT_PROJECT_RESULTS_DIR", ""), f"{DEFAULT_PROJECT_PATH}/sub_agent_results")
SUB_AGENT_MAX_ACTIVE = int(os.environ.get("SUB_AGENT_MAX_ACTIVE", "5"))
def resolve_sub_agent_models_config() -> str:
"""解析子智能体模型配置文件路径,回退链(高→低):
1. ``~/.agents/<mode>/config/sub_agent_models.json``部署者真实配置
2. 源码树 ``config/sub_agent_models.json``仓库内种子
3. 源码树 ``easyagent/models.json``旧版 easyagent 配置位置
4. 源码树 ``config/sub_agent_models.json.example``示例兜底
都不存在时返回部署目录下的目标路径由调用方处理不存在
"""
# 先走标准回退链:部署 → config/种子 → config/.example
standard = resolve_deploy_config("sub_agent_models.json")
standard_path = Path(standard)
if standard_path.exists():
return str(standard_path)
# 最后回退到旧 easyagent/models.json
legacy = _REPO_ROOT / "easyagent" / "models.json"
if legacy.exists():
return str(legacy)
return standard # 返回部署目录路径,由调用方处理不存在
# 子智能体模型配置文件(可通过环境变量覆盖,否则走回退链解析)
SUB_AGENT_MODELS_CONFIG_FILE = os.environ.get("SUB_AGENT_MODELS_CONFIG_FILE", "") or resolve_sub_agent_models_config()
__all__ = [
"SUB_AGENT_SERVICE_BASE_URL",
"SUB_AGENT_DEFAULT_TIMEOUT",
@ -25,4 +58,6 @@ __all__ = [
"SUB_AGENT_PROJECT_RESULTS_DIR",
"SUB_AGENT_STATE_FILE",
"SUB_AGENT_MAX_ACTIVE",
"SUB_AGENT_MODELS_CONFIG_FILE",
"resolve_sub_agent_models_config",
]

View File

@ -0,0 +1,15 @@
{
"tavily_api_key": "",
"default_model": "",
"models": [
{
"url": "https://api.example.com/v1",
"name": "example-model",
"apikey": "${YOUR_API_KEY_ENV}",
"modes": "快速,思考",
"multimodal": "",
"max_output": 32000,
"max_context": 256000
}
]
}

View File

@ -1,6 +1,6 @@
{
"tavily_api_key": "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",
"default_model": "kimi-k2.5",
"default_model": "deepseek-v4-flash",
"models": [
{
"url": "https://coding.dashscope.aliyuncs.com/v1",
@ -12,11 +12,11 @@
"max_context": 256000
},
{
"url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"name": "qwen3.5-plus",
"apikey": "sk-64af1343e67d46d7a902ef5bcf6817ad",
"url": "https://opencode.ai/zen/go/v1",
"name": "deepseek-v4-flash",
"apikey": "sk-j0NdTvEDoqqkKCHEAFXXYneEsuXEiOXNCgLeZARJmfYUBf2Riym7KPFWq1amkB6z",
"modes": "快速,思考",
"multimodal": "图片",
"multimodal": "",
"max_output": 32768,
"max_context": 256000
},

View File

@ -26,6 +26,7 @@ function parseArgs() {
agentId: null,
modelKey: null,
thinkingMode: null,
configFile: null,
timeout: 600,
};
@ -51,6 +52,8 @@ function parseArgs() {
config.thinkingMode = String(args[++i] || '').trim().toLowerCase();
} else if (arg === '--timeout' && i + 1 < args.length) {
config.timeout = parseInt(args[++i], 10);
} else if (arg === '--config-file' && i + 1 < args.length) {
config.configFile = args[++i];
}
}
@ -113,7 +116,7 @@ async function main() {
// 加载模型配置
const modelConfig = require('../config');
const ensuredConfig = modelConfig.ensureConfig();
const ensuredConfig = modelConfig.ensureConfig(config.configFile);
if (!ensuredConfig.valid_models || ensuredConfig.valid_models.length === 0) {
writeOutput(config.outputFile, {

View File

@ -98,14 +98,18 @@ function buildConfig(raw, filePath) {
};
}
function ensureConfig() {
const file = DEFAULT_CONFIG_PATH;
function ensureConfig(customPath) {
const file = customPath || DEFAULT_CONFIG_PATH;
if (!fs.existsSync(file)) {
const template = {
tavily_api_key: '',
default_model: '',
models: [],
};
const dir = path.dirname(file);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(file, JSON.stringify(template, null, 2), 'utf8');
}
const content = fs.readFileSync(file, 'utf8');

View File

@ -16,6 +16,7 @@ from config import (
OUTPUT_FORMATS,
SUB_AGENT_DEFAULT_TIMEOUT,
SUB_AGENT_MAX_ACTIVE,
SUB_AGENT_MODELS_CONFIG_FILE,
SUB_AGENT_STATE_FILE,
SUB_AGENT_STATUS_POLL_INTERVAL,
SUB_AGENT_TASKS_BASE_DIR,
@ -393,6 +394,7 @@ class SubAgentManager:
"--progress-file", progress_file,
"--agent-id", str(agent_id),
"--timeout", str(timeout_seconds),
"--config-file", SUB_AGENT_MODELS_CONFIG_FILE,
]
if model_key:
cmd.extend(["--model-key", model_key])