feat(024-generic-agent-interface-contrib): implement BaseAgent for fundamentals, sentiment, news, technical analysts
This commit is contained in:
parent
45d6dc22b7
commit
20686a2544
|
|
@ -12,7 +12,7 @@ No standardized input/output contract for agents. Hard to swap, compose, or benc
|
||||||
- [x] 1. Define AgentInput schema: ticker, date, context (market data, news, fundamentals)
|
- [x] 1. Define AgentInput schema: ticker, date, context (market data, news, fundamentals)
|
||||||
- [x] 2. Define AgentOutput schema: rating (5-tier), confidence, price_targets, thesis, risk_factors
|
- [x] 2. Define AgentOutput schema: rating (5-tier), confidence, price_targets, thesis, risk_factors
|
||||||
- [x] 3. Create BaseAgent abstract class with analyze(input) -> output contract
|
- [x] 3. Create BaseAgent abstract class with analyze(input) -> output contract
|
||||||
- [ ] 4. Refactor existing agents (fundamentals, sentiment, news, technical) to implement BaseAgent
|
- [x] 4. Refactor existing agents (fundamentals, sentiment, news, technical) to implement BaseAgent
|
||||||
- [ ] 5. Create AgentRegistry for pluggable agent discovery
|
- [ ] 5. Create AgentRegistry for pluggable agent discovery
|
||||||
- [ ] 6. Add agent benchmarking: compare outputs across different LLM backends
|
- [ ] 6. Add agent benchmarking: compare outputs across different LLM backends
|
||||||
- [ ] 7. Document interface for third-party agent contributions
|
- [ ] 7. Document interface for third-party agent contributions
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ from .analysts.fundamentals_analyst import create_fundamentals_analyst
|
||||||
from .analysts.market_analyst import create_market_analyst
|
from .analysts.market_analyst import create_market_analyst
|
||||||
from .analysts.news_analyst import create_news_analyst
|
from .analysts.news_analyst import create_news_analyst
|
||||||
from .analysts.social_media_analyst import create_social_media_analyst
|
from .analysts.social_media_analyst import create_social_media_analyst
|
||||||
|
from .analysts.base_analysts import (
|
||||||
|
FundamentalsAgent,
|
||||||
|
SentimentAgent,
|
||||||
|
NewsAgent,
|
||||||
|
TechnicalAgent,
|
||||||
|
)
|
||||||
|
|
||||||
from .researchers.bear_researcher import create_bear_researcher
|
from .researchers.bear_researcher import create_bear_researcher
|
||||||
from .researchers.bull_researcher import create_bull_researcher
|
from .researchers.bull_researcher import create_bull_researcher
|
||||||
|
|
@ -23,6 +29,10 @@ from .trader.trader import create_trader
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"BaseAgent",
|
"BaseAgent",
|
||||||
|
"FundamentalsAgent",
|
||||||
|
"SentimentAgent",
|
||||||
|
"NewsAgent",
|
||||||
|
"TechnicalAgent",
|
||||||
"FinancialSituationMemory",
|
"FinancialSituationMemory",
|
||||||
"AgentState",
|
"AgentState",
|
||||||
"AgentInput",
|
"AgentInput",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
"""BaseAgent implementations for the four analyst types.
|
||||||
|
|
||||||
|
Each class wraps the existing analyst logic behind the standardized
|
||||||
|
``BaseAgent.analyze(AgentInput) -> AgentOutput`` contract while the
|
||||||
|
original ``create_*`` factory functions remain unchanged for LangGraph
|
||||||
|
node compatibility.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from langchain_core.messages import HumanMessage
|
||||||
|
|
||||||
|
from tradingagents.agents.base_agent import BaseAgent
|
||||||
|
from tradingagents.agents.utils.schemas import AgentInput, AgentOutput
|
||||||
|
|
||||||
|
# Shared prompt that asks the LLM to return a JSON matching AgentOutput.
|
||||||
|
_STRUCTURED_SUFFIX = (
|
||||||
|
"\n\nAfter your analysis, provide a final JSON object with these exact keys:\n"
|
||||||
|
'- "rating": one of "BUY", "OVERWEIGHT", "HOLD", "UNDERWEIGHT", "SELL"\n'
|
||||||
|
'- "confidence": float 0.0-1.0\n'
|
||||||
|
'- "thesis": one-paragraph summary\n'
|
||||||
|
'- "risk_factors": list of strings\n'
|
||||||
|
"Return ONLY the JSON object, no other text."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _invoke_structured(llm, role_prompt: str, agent_input: AgentInput) -> AgentOutput:
|
||||||
|
"""Ask *llm* to produce an ``AgentOutput`` via structured output."""
|
||||||
|
full_prompt = (
|
||||||
|
f"{role_prompt}\n\n"
|
||||||
|
f"Ticker: {agent_input.ticker}\n"
|
||||||
|
f"Date: {agent_input.date}\n"
|
||||||
|
)
|
||||||
|
if agent_input.context:
|
||||||
|
for k, v in agent_input.context.items():
|
||||||
|
full_prompt += f"\n--- {k} ---\n{v}\n"
|
||||||
|
|
||||||
|
full_prompt += _STRUCTURED_SUFFIX
|
||||||
|
|
||||||
|
structured_llm = llm.with_structured_output(AgentOutput)
|
||||||
|
return structured_llm.invoke([HumanMessage(content=full_prompt)])
|
||||||
|
|
||||||
|
|
||||||
|
class FundamentalsAgent(BaseAgent):
|
||||||
|
"""Standardized fundamentals analyst."""
|
||||||
|
|
||||||
|
name: str = "fundamentals_analyst"
|
||||||
|
|
||||||
|
def __init__(self, llm) -> None:
|
||||||
|
self.llm = llm
|
||||||
|
|
||||||
|
def analyze(self, agent_input: AgentInput) -> AgentOutput:
|
||||||
|
return _invoke_structured(
|
||||||
|
self.llm,
|
||||||
|
"You are a fundamentals analyst. Evaluate the company's financial health "
|
||||||
|
"using balance sheets, cash flow, income statements, and key ratios.",
|
||||||
|
agent_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SentimentAgent(BaseAgent):
|
||||||
|
"""Standardized sentiment / social-media analyst."""
|
||||||
|
|
||||||
|
name: str = "sentiment_analyst"
|
||||||
|
|
||||||
|
def __init__(self, llm) -> None:
|
||||||
|
self.llm = llm
|
||||||
|
|
||||||
|
def analyze(self, agent_input: AgentInput) -> AgentOutput:
|
||||||
|
return _invoke_structured(
|
||||||
|
self.llm,
|
||||||
|
"You are a sentiment analyst. Evaluate public sentiment from social media, "
|
||||||
|
"news headlines, and community discussions about the company.",
|
||||||
|
agent_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NewsAgent(BaseAgent):
|
||||||
|
"""Standardized news analyst."""
|
||||||
|
|
||||||
|
name: str = "news_analyst"
|
||||||
|
|
||||||
|
def __init__(self, llm) -> None:
|
||||||
|
self.llm = llm
|
||||||
|
|
||||||
|
def analyze(self, agent_input: AgentInput) -> AgentOutput:
|
||||||
|
return _invoke_structured(
|
||||||
|
self.llm,
|
||||||
|
"You are a news analyst. Evaluate recent news, macroeconomic events, "
|
||||||
|
"and geopolitical developments relevant to the company.",
|
||||||
|
agent_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TechnicalAgent(BaseAgent):
|
||||||
|
"""Standardized technical / market analyst."""
|
||||||
|
|
||||||
|
name: str = "technical_analyst"
|
||||||
|
|
||||||
|
def __init__(self, llm) -> None:
|
||||||
|
self.llm = llm
|
||||||
|
|
||||||
|
def analyze(self, agent_input: AgentInput) -> AgentOutput:
|
||||||
|
return _invoke_structured(
|
||||||
|
self.llm,
|
||||||
|
"You are a technical analyst. Evaluate price action, volume, moving averages, "
|
||||||
|
"MACD, RSI, Bollinger Bands, and other technical indicators.",
|
||||||
|
agent_input,
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue