From 15bd9d06a78418dfb5d3e00eade3827a06d83b42 Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 28 Sep 2025 16:34:11 +0800 Subject: [PATCH] update --- app/llm/prompts.py | 9 ++++ app/utils/config.py | 105 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 106 insertions(+), 8 deletions(-) diff --git a/app/llm/prompts.py b/app/llm/prompts.py index 53d980c..48a08b5 100644 --- a/app/llm/prompts.py +++ b/app/llm/prompts.py @@ -24,12 +24,21 @@ def department_prompt(settings: "DepartmentSettings", context: "DepartmentContex market_lines = "\n".join( f"- {key}: {value}" for key, value in sorted(context.market_snapshot.items()) ) + scope_lines = "\n".join(f"- {item}" for item in settings.data_scope) + role_description = settings.description.strip() + role_instruction = settings.prompt.strip() instructions = f""" 部门名称:{settings.title} 股票代码:{context.ts_code} 交易日:{context.trade_date} +角色说明:{role_description or '未配置,默认沿用部门名称所代表的研究职责。'} +职责指令:{role_instruction or '在保持部门风格的前提下,结合可用数据做出审慎判断。'} + +【可用数据范围】 +{scope_lines or '- 使用系统提供的全部上下文,必要时指出仍需的额外数据。'} + 【核心特征】 {feature_lines or '- (无)'} diff --git a/app/utils/config.py b/app/utils/config.py index a1f51b7..bad481b 100644 --- a/app/utils/config.py +++ b/app/utils/config.py @@ -5,7 +5,7 @@ from dataclasses import dataclass, field import json import os from pathlib import Path -from typing import Dict, List, Optional +from typing import Dict, Iterable, List, Optional def _default_root() -> Path: @@ -186,19 +186,102 @@ class DepartmentSettings: title: str description: str = "" weight: float = 1.0 + data_scope: List[str] = field(default_factory=list) + prompt: str = "" llm: LLMConfig = field(default_factory=LLMConfig) def _default_departments() -> Dict[str, DepartmentSettings]: presets = [ - ("momentum", "动量策略部门"), - ("value", "价值评估部门"), - ("news", "新闻情绪部门"), - ("liquidity", "流动性评估部门"), - ("macro", "宏观研究部门"), - ("risk", "风险控制部门"), + { + "code": "momentum", + "title": "动量策略部门", + "description": "跟踪价格动量与量价共振,评估短线趋势延续的概率。", + "data_scope": [ + "daily.close", + "daily.open", + "daily_basic.turnover_rate", + "factors.mom_20", + "factors.mom_60", + ], + "prompt": "你主导动量风格研究,关注价格与成交量的加速变化,需在保持纪律的前提下判定短期多空倾向。", + }, + { + "code": "value", + "title": "价值评估部门", + "description": "衡量估值水平与盈利质量,为中期配置提供性价比判断。", + "data_scope": [ + "daily_basic.pe", + "daily_basic.pb", + "daily_basic.roe", + "fundamental.growth", + ], + "prompt": "你负责价值与质量评估,应结合估值分位、盈利持续性及安全边际给出配置建议。", + }, + { + "code": "news", + "title": "新闻情绪部门", + "description": "监控舆情热度与事件影响,识别情绪驱动的短期风险与机会。", + "data_scope": [ + "news.sentiment_index", + "news.heat_score", + "events.latest_headlines", + ], + "prompt": "你专注新闻和事件驱动,应评估正负面舆情对标的短线波动的可能影响。", + }, + { + "code": "liquidity", + "title": "流动性评估部门", + "description": "衡量成交活跃度与交易成本,控制进出场的实现可能性。", + "data_scope": [ + "daily_basic.volume_ratio", + "daily_basic.turnover_rate_f", + "market.spread_estimate", + ], + "prompt": "你负责评估该标的的流动性与滑点风险,需要提出可执行的仓位调整建议。", + }, + { + "code": "macro", + "title": "宏观研究部门", + "description": "追踪宏观与行业景气度,为行业配置和风险偏好提供参考。", + "data_scope": [ + "macro.industry_heat", + "macro.liquidity_cycle", + "index.performance_peers", + ], + "prompt": "你负责宏观与行业研判,应结合宏观周期、行业景气与相对强弱给出方向性意见。", + }, + { + "code": "risk", + "title": "风险控制部门", + "description": "监控极端风险、合规与交易限制,必要时行使否决。", + "data_scope": [ + "market.limit_flags", + "portfolio.position", + "risk.alerts", + ], + "prompt": "你负责风险控制,应识别停牌、涨跌停、持仓约束等因素,必要时提出减仓或观望建议。", + }, ] - return {code: DepartmentSettings(code=code, title=title) for code, title in presets} + return { + item["code"]: DepartmentSettings( + code=item["code"], + title=item["title"], + description=item.get("description", ""), + data_scope=list(item.get("data_scope", [])), + prompt=item.get("prompt", ""), + ) + for item in presets + } + + +def _normalize_data_scope(raw: object) -> List[str]: + if isinstance(raw, str): + tokens = raw.replace(";", "\n").replace(",", "\n").splitlines() + return [token.strip() for token in tokens if token.strip()] + if isinstance(raw, Iterable) and not isinstance(raw, (bytes, bytearray, str)): + return [str(item).strip() for item in raw if str(item).strip()] + return [] @dataclass @@ -388,6 +471,8 @@ def _load_from_file(cfg: AppConfig) -> None: title = data.get("title") or code description = data.get("description") or "" weight = float(data.get("weight", 1.0)) + prompt_text = str(data.get("prompt") or "") + data_scope = _normalize_data_scope(data.get("data_scope")) llm_cfg = LLMConfig() route_name = data.get("llm_route") resolved_cfg = None @@ -420,6 +505,8 @@ def _load_from_file(cfg: AppConfig) -> None: title=title, description=description, weight=weight, + data_scope=data_scope, + prompt=prompt_text, llm=resolved_cfg, ) if new_departments: @@ -451,6 +538,8 @@ def save_config(cfg: AppConfig | None = None) -> None: "title": dept.title, "description": dept.description, "weight": dept.weight, + "data_scope": list(dept.data_scope), + "prompt": dept.prompt, "llm": { "strategy": dept.llm.strategy if dept.llm.strategy in ALLOWED_LLM_STRATEGIES else "single", "majority_threshold": dept.llm.majority_threshold,