Files
group_fqcd_jr/app/service/agent/implementations/advisor.py
T

71 lines
3.2 KiB
Python
Raw Normal View History

2026-09-11 13:11:58 +08:00
"""投顾 Agent 的公共底座实现。"""
2026-09-11 11:49:11 +08:00
2026-09-11 13:11:58 +08:00
from typing import Any
2026-09-11 11:49:11 +08:00
2026-09-11 13:11:58 +08:00
from app.core.contracts import AgentDefinition, AgentRequest, CoreResult, RequestContext
2026-09-11 11:49:11 +08:00
from app.service.agent.implementations.fund_query_demo import FundQueryDemoAgent
class AdvisorAgent(FundQueryDemoAgent):
"""通过公共 BaseAgent 链路运行的最小投顾 Agent。"""
definition = AgentDefinition(
agent_type="advisor",
version="0.1.0",
allowed_roles=("customer", "advisor", "operator", "admin"),
allowed_portals=("api",),
2026-09-11 13:20:09 +08:00
allowed_tools=("query_fund_quote", "query_investment_goal", "analyze_portfolio"),
supported_intents=("fund_quote", "investment_goal", "portfolio_analysis"),
2026-09-11 11:49:11 +08:00
)
2026-09-11 13:11:58 +08:00
async def handle(self, request: AgentRequest, context: RequestContext) -> CoreResult:
if (
self._classified_intent is not None
and self._classified_intent.intent == "investment_goal"
):
output = await self.call_tool(
"query_investment_goal", {}, intent="investment_goal", context=context
)
if not isinstance(output, dict):
return CoreResult(text="当前没有已确认的投资目标,暂不能用于配置或产品推荐。")
return CoreResult(text=self._describe_goal(output))
2026-09-11 13:20:09 +08:00
if (
self._classified_intent is not None
and self._classified_intent.intent == "portfolio_analysis"
):
output = await self.call_tool(
"analyze_portfolio", {}, intent="portfolio_analysis", context=context
)
return CoreResult(text=self._describe_portfolio(output))
2026-09-11 13:11:58 +08:00
return await super().handle(request, context)
@staticmethod
def _describe_goal(goal: dict[str, Any]) -> str:
return (
f"当前投资目标:年化收益目标 {goal['annualized_return_lower_pct']}%-"
f"{goal['annualized_return_upper_pct']}%,最大回撤 {goal['max_drawdown_pct']}%,"
f"流动性要求 {goal['liquidity_requirement']},投资期限 "
f"{goal['investment_horizon_months']} 个月,业绩比较基准 {goal['benchmark_name']}。"
"以上为目标采集结果,不构成收益承诺或交易指令。"
)
2026-09-11 13:20:09 +08:00
@staticmethod
def _describe_portfolio(result: object) -> str:
if not isinstance(result, dict):
return "持仓分析暂不可用,请稍后重试。"
status = result.get("status")
if status == "no_positions":
return "当前没有可分析的场内基金持仓。"
if status == "valuation_required":
return "当前持仓缺少可用市值,暂不能计算集中度。"
summary = result.get("summary")
if not isinstance(summary, dict):
return "持仓分析数据不完整,请稍后重试。"
concentration = result.get("product_concentration")
hhi = concentration.get("hhi") if isinstance(concentration, dict) else None
return (
f"持仓分析完成:共 {summary.get('position_count')} 个产品,"
f"总市值 {summary.get('total_market_value')},产品集中度 HHI 为 {hhi}。"
"分析结果仅供参考,不生成交易指令。"
)