Skip to content

Commit d1ada52

Browse files
UserUser
authored andcommitted
fix: use LiteLLM response_format for proper JSON responses from GPT models
- Added response_format parameter to force JSON responses from GPT models - Removed custom markdown stripping workaround - Ensures clean JSON parsing without markdown wrapper issues
1 parent ba3fd24 commit d1ada52

9 files changed

Lines changed: 1266 additions & 0 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ venv.bak/
7171
*.pdf
7272
ACE_IMPROVEMENTS.md
7373
ACE_ROADMAP.md
74+
DEMO_TODO.md
7475
*.egg-info/
7576
reports/
7677
docs/method_outline.md

ace/llm_providers/litellm_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ def complete(self, prompt: str, **kwargs: Any) -> LLMResponse:
222222
"num_retries": kwargs.get("num_retries", self.config.max_retries),
223223
}
224224

225+
# Force JSON response for models that support it
226+
if "gpt" in self.config.model.lower() and "json" in prompt.lower():
227+
call_params["response_format"] = {"type": "json_object"}
228+
225229
# Add API key if available
226230
if self.config.api_key:
227231
call_params["api_key"] = self.config.api_key
@@ -291,6 +295,10 @@ async def acomplete(self, prompt: str, **kwargs: Any) -> LLMResponse:
291295
"num_retries": kwargs.get("num_retries", self.config.max_retries),
292296
}
293297

298+
# Force JSON response for models that support it
299+
if "gpt" in self.config.model.lower() and "json" in prompt.lower():
300+
call_params["response_format"] = {"type": "json_object"}
301+
294302
# Add API key if available
295303
if self.config.api_key:
296304
call_params["api_key"] = self.config.api_key

examples/kayba_test_auto.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python3
2+
"""
3+
🌊 The Kayba Test - True Auto-Learning 🌊
4+
==========================================
5+
No training. Just learning from mistakes.
6+
"""
7+
8+
import os
9+
try:
10+
from dotenv import load_dotenv
11+
load_dotenv()
12+
except ImportError:
13+
pass
14+
15+
from rich.console import Console
16+
from rich.panel import Panel
17+
18+
from ace import Generator, Reflector, Curator, Playbook
19+
from ace import TaskEnvironment, EnvironmentResult
20+
from ace.llm_providers import LiteLLMClient
21+
from ace.adaptation import Sample
22+
23+
console = Console()
24+
25+
26+
class SimpleEnvironment(TaskEnvironment):
27+
"""Just checks if the answer is correct."""
28+
29+
def evaluate(self, sample: Sample, generator_output):
30+
response = generator_output.final_answer.lower()
31+
32+
if "no" in response and "seahorse" in response:
33+
return EnvironmentResult(
34+
feedback="✅ Correct!",
35+
ground_truth="No seahorse emoji exists",
36+
metrics={"accuracy": 1.0}
37+
)
38+
else:
39+
return EnvironmentResult(
40+
feedback="❌ Wrong. There is no seahorse emoji.",
41+
ground_truth="No seahorse emoji exists",
42+
metrics={"accuracy": 0.0}
43+
)
44+
45+
46+
def main():
47+
console.print("[bold cyan]🌊 Kayba Test - Auto-Learning Demo[/bold cyan]\n")
48+
49+
# Setup
50+
client = LiteLLMClient(model="gpt-4o", temperature=0.3, max_tokens=1000)
51+
generator = Generator(client)
52+
reflector = Reflector(client)
53+
curator = Curator(client)
54+
playbook = Playbook()
55+
environment = SimpleEnvironment()
56+
57+
question = "Is there a seahorse emoji?"
58+
sample = Sample(question=question)
59+
60+
# First ask
61+
console.print("[yellow]Round 1:[/yellow] Asking with empty playbook...")
62+
console.print(f"[bold]Question:[/bold] {question}")
63+
output1 = generator.generate(question=question, context="", playbook=playbook)
64+
console.print(f"[bold]Full Response:[/bold] {output1.final_answer}")
65+
console.print(f"[dim]Reasoning: {output1.reasoning}[/dim]")
66+
67+
# Check if correct
68+
result1 = environment.evaluate(sample, output1)
69+
console.print(result1.feedback)
70+
71+
# If wrong, ACE learns automatically
72+
if result1.metrics["accuracy"] < 1.0:
73+
console.print("\n[cyan]ACE is reflecting on the mistake...[/cyan]")
74+
75+
# Reflect
76+
reflection = reflector.reflect(
77+
question=question,
78+
generator_output=output1,
79+
playbook=playbook,
80+
ground_truth=result1.ground_truth,
81+
feedback=result1.feedback
82+
)
83+
84+
# Update playbook
85+
curator_output = curator.curate(
86+
reflection=reflection,
87+
playbook=playbook,
88+
question_context="emoji questions",
89+
progress="learning"
90+
)
91+
playbook.apply_delta(curator_output.delta)
92+
93+
console.print(f"[green]Playbook updated with {len(playbook.bullets())} insights[/green]")
94+
95+
# Show the playbook contents
96+
if len(playbook.bullets()) > 0:
97+
console.print("\n[cyan]📚 Current Playbook:[/cyan]")
98+
console.print(Panel(playbook.as_prompt(), style="cyan"))
99+
100+
# Second ask - should use playbook
101+
console.print(f"\n[yellow]Round 2:[/yellow] Asking again with {len(playbook.bullets())} learned insights...")
102+
console.print(f"[bold]Question:[/bold] {question}")
103+
output2 = generator.generate(question=question, context="", playbook=playbook)
104+
console.print(f"[bold]Full Response:[/bold] {output2.final_answer}")
105+
console.print(f"[dim]Reasoning: {output2.reasoning}[/dim]")
106+
if output2.bullet_ids:
107+
console.print(f"[dim]Used bullets: {output2.bullet_ids}[/dim]")
108+
109+
# Check if correct now
110+
result2 = environment.evaluate(sample, output2)
111+
console.print(result2.feedback)
112+
113+
if result2.metrics["accuracy"] > result1.metrics["accuracy"]:
114+
console.print("\n[bold green]✅ ACE learned from its mistake![/bold green]")
115+
else:
116+
console.print("\n[yellow]ACE needs more examples to learn this fact.[/yellow]")
117+
118+
119+
if __name__ == "__main__":
120+
main()

0 commit comments

Comments
 (0)