Diversify AI predictions via per-model analyst personas
GPT (data-driven), Claude (tactical/upset-aware), Gemini (attacking-minded) each get a distinct perspective so the 3 picks genuinely diverge instead of producing identical scorelines. Honest: still each model's own judgment. Finished matches are untouched (generation filters result_outcome IS NULL). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>develop
parent
0f055dace1
commit
1d406f6a4e
|
|
@ -32,10 +32,33 @@ class MatchContext:
|
||||||
kickoff: str # ISO
|
kickoff: str # ISO
|
||||||
|
|
||||||
|
|
||||||
def _prompt(ctx: MatchContext) -> str:
|
# 모델별 분석 관점(페르소나) — 동일 경기라도 서로 다른 시각으로 보게 해
|
||||||
|
# 예측이 자연스럽게 갈리도록 한다(강제 분산이 아니라 진짜 판단의 다양화).
|
||||||
|
PERSONA = {
|
||||||
|
"GPT": (
|
||||||
|
"You are a DATA-DRIVEN analyst. Base your call on recent form, head-to-head, "
|
||||||
|
"FIFA ranking gaps and goals-scored/conceded trends. Be objective and "
|
||||||
|
"evidence-led; pick the scoreline the numbers most support."
|
||||||
|
),
|
||||||
|
"Claude": (
|
||||||
|
"You are a TACTICAL analyst. Focus on matchups, defensive organization, "
|
||||||
|
"midfield control and game-state. Take low-scoring games, tight margins and "
|
||||||
|
"genuine upset potential seriously — do not just rubber-stamp the favorite."
|
||||||
|
),
|
||||||
|
"Gemini": (
|
||||||
|
"You are an ATTACKING-MINDED analyst. Weigh momentum, attacking quality, "
|
||||||
|
"star players and scoring potential. Lean toward open, higher-scoring "
|
||||||
|
"scenarios when the talent and tempo justify it."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _prompt(ctx: MatchContext, persona: str) -> str:
|
||||||
return (
|
return (
|
||||||
f"You are a football match analyst. Predict the result of this "
|
f"{persona}\n"
|
||||||
f"2026 FIFA World Cup match.\n"
|
f"Predict the result of this 2026 FIFA World Cup match using YOUR perspective "
|
||||||
|
f"above. Judge independently — it is fine to differ from the obvious consensus "
|
||||||
|
f"pick when your perspective warrants it.\n"
|
||||||
f"Team A: {ctx.team_a}\nTeam B: {ctx.team_b}\n"
|
f"Team A: {ctx.team_a}\nTeam B: {ctx.team_b}\n"
|
||||||
f"Venue: {ctx.venue}\nKickoff: {ctx.kickoff}\n"
|
f"Venue: {ctx.venue}\nKickoff: {ctx.kickoff}\n"
|
||||||
f"Important: World Cup group-stage matches are played at NEUTRAL venues. "
|
f"Important: World Cup group-stage matches are played at NEUTRAL venues. "
|
||||||
|
|
@ -96,7 +119,7 @@ async def predict_gpt(ctx: MatchContext) -> dict:
|
||||||
model=settings.openai_model,
|
model=settings.openai_model,
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": "You output only valid JSON."},
|
{"role": "system", "content": "You output only valid JSON."},
|
||||||
{"role": "user", "content": _prompt(ctx)},
|
{"role": "user", "content": _prompt(ctx, PERSONA["GPT"])},
|
||||||
],
|
],
|
||||||
response_format={"type": "json_object"},
|
response_format={"type": "json_object"},
|
||||||
)
|
)
|
||||||
|
|
@ -116,7 +139,7 @@ async def predict_claude(ctx: MatchContext) -> dict:
|
||||||
return await client.messages.create(
|
return await client.messages.create(
|
||||||
model=settings.anthropic_model,
|
model=settings.anthropic_model,
|
||||||
max_tokens=1024,
|
max_tokens=1024,
|
||||||
messages=[{"role": "user", "content": _prompt(ctx)}],
|
messages=[{"role": "user", "content": _prompt(ctx, PERSONA["Claude"])}],
|
||||||
**extra,
|
**extra,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -143,7 +166,7 @@ async def predict_gemini(ctx: MatchContext) -> dict:
|
||||||
client = genai.Client(api_key=settings.google_api_key)
|
client = genai.Client(api_key=settings.google_api_key)
|
||||||
resp = await client.aio.models.generate_content(
|
resp = await client.aio.models.generate_content(
|
||||||
model=settings.google_model,
|
model=settings.google_model,
|
||||||
contents=_prompt(ctx),
|
contents=_prompt(ctx, PERSONA["Gemini"]),
|
||||||
config=types.GenerateContentConfig(response_mime_type="application/json"),
|
config=types.GenerateContentConfig(response_mime_type="application/json"),
|
||||||
)
|
)
|
||||||
return _normalize(json.loads(resp.text or "{}"))
|
return _normalize(json.loads(resp.text or "{}"))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue