This commit is contained in:
sam 2025-10-06 15:13:19 +08:00
parent c45026eff4
commit 8f8e54e0bd
5 changed files with 188 additions and 0 deletions

View File

@ -0,0 +1,31 @@
{
"department_base": {
"name": "部门基础模板",
"description": "审慎分析骨架(数据校验强化版)",
"template": "部门:{title}\n股票代码{ts_code}\n交易日{trade_date}\n\n【角色定位】\n- 角色说明:{description}\n- 行动守则:{instruction}\n\n【数据校验】\n1. 逐条确认提供的数据是否符合 expected schema缺失项需记录在 `risks`。\n2. 如出现冲突数据,请在 `signals` 中说明解决思路,并指出最可信的来源。\n\n【数据边界】\n- 可用字段:\n{data_scope}\n- 核心特征:\n{features}\n- 市场背景:\n{market_snapshot}\n- 追加数据:\n{supplements}\n\n【分析步骤】\n1. 评估数据完整度,必要时建议补充 `fetch_data` 的具体调用参数。\n2. 基于量化证据拆分 2-3 个关键支撑与潜在风险,注明对应字段。\n3. 提炼操作建议并给出可执行的风险对冲或观察指标。\n\n【输出要求】\n仅返回一个 JSON 对象,不要添加额外文本:\n{\n \"action\": \"BUY|BUY_S|BUY_M|BUY_L|SELL|HOLD\",\n \"confidence\": 0-1 之间的小数,\n \"summary\": \"一句话结论\",\n \"signals\": [\"字段+现象\", \"...\"],\n \"risks\": [\"字段+风险\", \"...\"]\n}\n如需说明未完成的数据请求请在 `risks` 中补充。",
"variables": [
"title",
"ts_code",
"trade_date",
"description",
"instruction",
"data_scope",
"features",
"market_snapshot",
"supplements"
],
"max_length": 4000,
"required_context": [
"ts_code",
"trade_date",
"features",
"market_snapshot"
],
"version": "1.1.0",
"metadata": {
"label": "quality_guard",
"notes": "强调数据校验与风险映射。"
},
"activate": false
}
}

View File

@ -0,0 +1,31 @@
{
"department_base": {
"name": "部门基础模板",
"description": "审慎分析骨架(结构化输出版)",
"template": "部门:{title}\n股票代码{ts_code}\n交易日{trade_date}\n\n【角色定位】\n- 研究职责:{description}\n- 执行要点:{instruction}\n\n【量化检查】\n- 数据覆盖:\n{data_scope}\n- 模型特征:\n{features}\n- 市场切片:\n{market_snapshot}\n- 附加观察:\n{supplements}\n\n【分析流程】\n1. 使用事实句描述当前市场位置(包含至少 1 项相对指标)。\n2. 归纳 2-3 条策略信号,每条需关联具体字段并给出方向。\n3. 对每条信号列出对应的风险验证指标与触发阈值。\n4. 最终给出操作建议,并在 `confidence` 中量化判断依据。\n\n【输出格式】\n仅输出 JSON不包含额外文字\n{\n \"action\": \"BUY|BUY_S|BUY_M|BUY_L|SELL|HOLD\",\n \"confidence\": 小数,\n \"summary\": \"一句话\",\n \"signals\": [\n {\n \"statement\": \"现象描述\",\n \"evidence\": \"对应字段或数据来源\",\n \"direction\": \"bullish|bearish|neutral\"\n }\n ],\n \"risks\": [\n {\n \"threat\": \"风险描述\",\n \"monitor\": \"观测指标\",\n \"threshold\": \"触发阈值\"\n }\n ]\n}\n若缺少关键数据请在 `risks` 中新增一项 `monitor` 为 `data_gap`。",
"variables": [
"title",
"ts_code",
"trade_date",
"description",
"instruction",
"data_scope",
"features",
"market_snapshot",
"supplements"
],
"max_length": 4000,
"required_context": [
"ts_code",
"trade_date",
"features",
"market_snapshot"
],
"version": "1.2.0",
"metadata": {
"label": "structured_v2",
"notes": "增加信号与风险的结构化字段。"
},
"activate": true
}
}

View File

@ -0,0 +1,28 @@
{
"momentum_dept": {
"name": "动量研究部门模板",
"description": "多层级动量评估版本",
"template": "部门:动量研究部门\n股票代码{ts_code}\n交易日{trade_date}\n\n【角色定位】\n- 追踪价格与成交量动量的共振与切换。\n- 识别趋势衰减与阶段性反转信号。\n\n【分层动量视角】\n1. 超短线1-3 日)动量:\n{features}\n2. 短线5-10 日)趋势斜率:\n{market_snapshot}\n3. 中线20+ 日)位置与乖离:\n{data_scope}\n\n【执行指引】\n- 对每个时间层给出强度评级strong/weak/neutral。\n- 若评级存在冲突,需在 `risks` 说明优先采信的层级。\n- 必须评估量价背离与成交密集区。\n\n【输出要求】\n仅输出 JSON\n{\n \"action\": \"BUY|BUY_S|BUY_M|BUY_L|SELL|HOLD\",\n \"confidence\": 小数,\n \"summary\": \"一句话\",\n \"signals\": [\"层级+观察\", \"...\"],\n \"risks\": [\"层级+风险\", \"...\"]\n}\n若需进一步数据请在 `risks` 中注明具体字段。",
"variables": [
"ts_code",
"trade_date",
"data_scope",
"features",
"market_snapshot",
"supplements"
],
"max_length": 4000,
"required_context": [
"ts_code",
"trade_date",
"features",
"market_snapshot"
],
"version": "1.1.0",
"metadata": {
"label": "multiframe",
"notes": "分层动量分析,强调评级冲突解释。"
},
"activate": false
}
}

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import json
import logging
from pathlib import Path
from dataclasses import dataclass
from typing import Any, Dict, List, Optional, TYPE_CHECKING
@ -633,4 +634,59 @@ def register_default_templates() -> None:
# Auto-register default templates on module import
EXTERNAL_TEMPLATE_DIR = Path(__file__).resolve().parents[1] / "data" / "prompt_templates"
def load_external_template_configs(directory: Path | str = EXTERNAL_TEMPLATE_DIR) -> None:
"""Load additional template versions from JSON files in the given directory."""
directory_path = Path(directory)
if not directory_path.exists() or not directory_path.is_dir():
return
for file_path in sorted(directory_path.glob("*.json")):
try:
raw_data = file_path.read_text(encoding="utf-8")
except OSError:
logging.warning("无法读取提示模板配置文件 %s", file_path)
continue
try:
payload = json.loads(raw_data)
except json.JSONDecodeError as exc:
logging.warning("提示模板配置文件 %s 解析失败:%s", file_path, exc)
continue
enriched_payload = {}
for template_id, cfg in payload.items():
if not isinstance(cfg, dict):
logging.warning(
"提示模板配置文件 %s 中的 %s 配置无效(应为对象)",
file_path,
template_id,
)
continue
metadata = cfg.get("metadata") or {}
if not isinstance(metadata, dict):
metadata = {}
metadata.setdefault("source", file_path.name)
enriched_payload[template_id] = {
**cfg,
"metadata": metadata,
}
if not enriched_payload:
continue
try:
TemplateRegistry.load_from_json(json.dumps(enriched_payload, ensure_ascii=False))
except Exception as exc: # noqa: BLE001
logging.warning(
"注册提示模板配置 %s 失败:%s",
file_path,
exc,
)
register_default_templates()
load_external_template_configs()

View File

@ -25,6 +25,7 @@ from app.ingest.tushare import run_ingestion
from app.llm.client import run_llm
from app.llm.metrics import reset as reset_llm_metrics
from app.llm.metrics import snapshot as snapshot_llm_metrics
from app.llm.templates import TemplateRegistry
from app.utils import alerts
from app.utils.config import get_config, save_config
from app.utils.tuning import log_tuning_result
@ -464,6 +465,47 @@ def render_backtest_review() -> None:
spec_labels.append(f"department:{dept_code}:tool_choice")
action_values.append(tool_value)
template_id = (settings.prompt_template_id or f"{dept_code}_dept").strip()
versions = [ver for ver in TemplateRegistry.list_versions(template_id) if isinstance(ver, str)]
if versions:
active_version = TemplateRegistry.get_active_version(template_id)
default_version = (
settings.prompt_template_version
or active_version
or versions[0]
)
try:
default_index = versions.index(default_version)
except ValueError:
default_index = 0
version_choice = st.selectbox(
"提示模板版本",
versions,
index=default_index,
key=f"{prefix}_template_version",
help="离散动作将按版本列表顺序映射,可用于强化学习优化。",
)
selected_index = versions.index(version_choice)
ratio = (
0.0
if len(versions) == 1
else selected_index / (len(versions) - 1)
)
specs.append(
ParameterSpec(
name=f"dept_prompt_version_{dept_code}",
target=f"department.{dept_code}.prompt_template_version",
values=list(versions),
)
)
spec_labels.append(f"department:{dept_code}:prompt_version")
action_values.append(ratio)
st.caption(
f"激活版本:{active_version or '默认'} 当前选择:{version_choice}"
)
else:
st.caption("当前模板未注册可选提示词版本,继续沿用激活版本。")
if specs:
st.caption("动作维度顺序:" + "".join(spec_labels))