In diesem Tutorial arbeiten wir direkt mit dem A-Evolve Framework in Colab und erstellen Sie von Grund auf eine vollständige Pipeline für evolutionäre Agenten. Wir richten das Repository ein, konfigurieren einen OpenAI-basierten Agenten, definieren einen benutzerdefinierten Benchmark und bauen unsere eigene Evolutions-Engine, um zu sehen, wie A-Evolve einen Agenten durch iterative Arbeitsbereichsmutationen tatsächlich verbessert. Durch den Code nutzen wir die Kernabstraktionen des Frameworks für Eingabeaufforderungen, Fähigkeiten, Speicher, Benchmarking und Entwicklung, die uns nicht nur helfen, zu verstehen, wie A-Evolve ausgeführt wird, sondern auch, wie es auf praktische, Colab-freundliche Weise erweitert werden kann.

import os
import sys
import json
import textwrap
import subprocess
import shutil
from pathlib import Path
from getpass import getpass
from collections import Counter, defaultdict


subprocess.check_call((sys.executable, "-m", "pip", "set up", "-q", "openai>=1.30.0", "pyyaml>=6.0", "matplotlib>=3.8"))
REPO_DIR = Path("/content material/a-evolve")
if REPO_DIR.exists():
   shutil.rmtree(REPO_DIR)
subprocess.check_call(("git", "clone", "--depth", "1", "https://github.com/A-EVO-Lab/a-evolve.git", str(REPO_DIR)))
sys.path.insert(0, str(REPO_DIR))


if not os.environ.get("OPENAI_API_KEY"):
   os.environ("OPENAI_API_KEY") = getpass("Enter your OpenAI API key: ").strip()


OPENAI_MODEL = "gpt-4o-mini"


import yaml
import matplotlib.pyplot as plt


import agent_evolve as ae
from agent_evolve.protocol.base_agent import BaseAgent
from agent_evolve.benchmarks.base import BenchmarkAdapter
from agent_evolve.engine.base import EvolutionEngine
from agent_evolve.sorts import Process, Trajectory, Suggestions, StepResult
from agent_evolve.contract.workspace import AgentWorkspace
from openai import OpenAI


shopper = OpenAI(api_key=os.environ("OPENAI_API_KEY"))


WORKSPACE_ROOT = Path("/content material/a_evolve_demo_workspace")
if WORKSPACE_ROOT.exists():
   shutil.rmtree(WORKSPACE_ROOT)


(WORKSPACE_ROOT / "prompts").mkdir(dad and mom=True, exist_ok=True)
(WORKSPACE_ROOT / "expertise").mkdir(dad and mom=True, exist_ok=True)
(WORKSPACE_ROOT / "reminiscence").mkdir(dad and mom=True, exist_ok=True)
(WORKSPACE_ROOT / "instruments").mkdir(dad and mom=True, exist_ok=True)


manifest = {
   "title": "colab-aevolve-demo-agent",
   "model": "0.1.0",
   "contract_version": "1.0",
   "agent": {
       "kind": "customized",
       "entrypoint": None
   },
   "evolvable_layers": ("prompts", "expertise", "reminiscence"),
   "reload_strategy": "sizzling"
}
with open(WORKSPACE_ROOT / "manifest.yaml", "w") as f:
   yaml.dump(manifest, f, sort_keys=False)


initial_system_prompt = textwrap.dedent("""
You're a exact text-transformation agent.


Remedy the duty precisely.
Be concise.
Return solely the ultimate reply with no rationalization except the duty explicitly asks for JSON.
""").strip()


(WORKSPACE_ROOT / "prompts" / "system.md").write_text(initial_system_prompt)

Wir bereiten die vollständige Colab-Umgebung vor, die zum Ausführen des Tutorials von Anfang bis Ende erforderlich ist. Wir installieren die erforderlichen Pakete, klonen das A-Evolve-Repository, laden die Framework-Importe und erfassen sicher den OpenAI-API-Schlüssel für den Modellzugriff. Wir definieren auch die Arbeitsbereichsstruktur und initialisieren das Manifest und die Systemeingabeaufforderung, um unserem sich entwickelnden Agenten einen gültigen Ausgangspunkt innerhalb des A-Evolve-Frameworks zu bieten.

def build_dataset():
   prepare = (
       {
           "id": "train-01",
           "rule": "json_sum",
           "enter": "Numbers: 7, 11, 4",
           "reply": '{"sum":22}'
       },
       {
           "id": "train-02",
           "rule": "json_sum",
           "enter": "Numbers: 20, 5, 3, 2",
           "reply": '{"sum":30}'
       },
       {
           "id": "train-03",
           "rule": "acronym_upper",
           "enter": "Create the acronym from: retrieval augmented technology",
           "reply": "RAG"
       },
       {
           "id": "train-04",
           "rule": "acronym_upper",
           "enter": "Create the acronym from: giant language mannequin",
           "reply": "LLM"
       },
       banana,
       zebra"
       ,
       {
           "id": "train-07",
           "rule": "vowel_parity",
           "enter": "Phrase: equation",
           "reply": "EVEN"
       },
       {
           "id": "train-08",
           "rule": "vowel_parity",
           "enter": "Phrase: schooling",
           "reply": "ODD"
       },
   )


   holdout = (
       {
           "id": "holdout-01",
           "rule": "json_sum",
           "enter": "Numbers: 100, 1, 9",
           "reply": '{"sum":110}'
       },
       {
           "id": "holdout-02",
           "rule": "acronym_upper",
           "enter": "Create the acronym from: synthetic normal intelligence",
           "reply": "AGI"
       },
       berry,
       {
           "id": "holdout-04",
           "rule": "vowel_parity",
           "enter": "Phrase: aeroplane",
           "reply": "ODD"
       },
   )
   return prepare, holdout


TRAIN_DATA, HOLDOUT_DATA = build_dataset()


def normalize_text(x: str) -> str:
   return x.strip().substitute(" ", "")


class MiniTextBenchmark(BenchmarkAdapter):
   def __init__(self):
       self.prepare = TRAIN_DATA
       self.holdout = HOLDOUT_DATA


   def get_tasks(self, cut up: str = "prepare", restrict: int = 10):
       knowledge = self.prepare if cut up == "prepare" else self.holdout
       duties = ()
       for row in knowledge(:restrict):
           duties.append(
               Process(
                   id=row("id"),
                   enter=row("enter"),
                   metadata={
                       "rule": row("rule"),
                       "reply": row("reply")
                   }
               )
           )
       return duties


   def consider(self, job: Process, trajectory: Trajectory):
       pred = trajectory.output.strip()
       gold = job.metadata("reply").strip()
       success = normalize_text(pred) == normalize_text(gold)
       element = {
           "rule": job.metadata("rule"),
           "gold": gold,
           "pred": pred,
           "enter": job.enter,
           "success": success
       }
       rating = 1.0 if success else 0.0
       return Suggestions(
           success=success,
           rating=rating,
           element=json.dumps(element, ensure_ascii=False),
           uncooked=element
       )


SKILL_ROUTING = {
   "json_sum": ("json", "sum"),
   "acronym_upper": ("acronym", "uppercase"),
   "pipe_unique_sorted_lower": ("distinctive", "sorted", "lowercase", "pipe"),
   "vowel_parity": ("vowel", "odd", "even", "parity")
}

Wir definieren die Trainings- und Holdout-Datensätze, die zur Messung des Agenten vor und nach der Evolution verwendet werden. Wir erstellen eine benutzerdefinierte Benchmark-Klasse, die jedes Beispiel in A-Evolve-Aufgaben verpackt und Vorhersagen anhand der genau erwarteten Ergebnisse bewertet. Wir richten außerdem Weiterleitungshinweise für Fertigkeiten ein, die das System darauf vorbereiten, später im Arbeitsablauf verschiedene Aufgabentypen mit den richtigen Verhaltensmustern zu verbinden.

class ColabAEResolverAgent(BaseAgent):
   def __init__(self, workspace_dir: str | Path, mannequin: str = OPENAI_MODEL):
       self.mannequin = mannequin
       tremendous().__init__(workspace_dir)


   def _pick_relevant_skills(self, job: Process):
       rule = job.metadata.get("rule", "")
       chosen = ()
       for ability in self.expertise:
           hay = f"{ability.title} {ability.description}".decrease()
           if rule == "json_sum" and ("json" in hay or "sum" in hay):
               chosen.append(ability)
           elif rule == "acronym_upper" and ("acronym" in hay or "uppercase" in hay):
               chosen.append(ability)
           elif rule == "pipe_unique_sorted_lower" and any(okay in hay for okay in ("distinctive", "sorted", "lowercase", "pipe")):
               chosen.append(ability)
           elif rule == "vowel_parity" and any(okay in hay for okay in ("vowel", "odd", "even", "parity")):
               chosen.append(ability)
       return chosen(:3)


   def remedy(self, job: Process) -> Trajectory:
       relevant_skills = self._pick_relevant_skills(job)
       relevant_skill_texts = ()
       for s in relevant_skills:
           relevant_skill_texts.append(self.get_skill_content(s.title))


       memory_text = "n".be a part of(
           (f"- {m.get('content material', '')}" for m in self.recollections(-8:))
       ).strip()


       skill_block = "nn".be a part of(relevant_skill_texts).strip()
       if not skill_block:
           skill_block = "(no expertise loaded but)"


       if not memory_text:
           memory_text = "(no reminiscence but)"


       user_prompt = textwrap.dedent(f"""
       TASK RULE: {job.metadata.get("rule")}
       TASK INPUT:
       {job.enter}


       ACTIVE SYSTEM PROMPT:
       {self.system_prompt}


       RELEVANT SKILLS:
       {skill_block}


       RECENT MEMORIES:
       {memory_text}


       Remedy the duty precisely.
       Return solely the ultimate reply.
       """).strip()


       response = shopper.chat.completions.create(
           mannequin=self.mannequin,
           temperature=0,
           messages=(
               {"function": "system", "content material": "You might be a precise text-transformation agent."},
               {"function": "consumer", "content material": user_prompt}
           )
       )


       output = (response.decisions(0).message.content material or "").strip()


       self.keep in mind(
           content material=f"Process {job.id} beneath rule {job.metadata.get('rule')} produced output: {output}",
           class="episodic"
       )


       return Trajectory(
           task_id=job.id,
           output=output,
           steps=(
               {
                   "rule": job.metadata.get("rule"),
                   "used_skills": (s.title for s in relevant_skills),
                   "system_prompt_chars": len(self.system_prompt),
                   "memory_items_seen": len(self.recollections)
               }
           )
       )


SKILL_TEMPLATES = {
   "json_sum": textwrap.dedent("""
       ---
       title: json-sum-exact
       description: Add all integers and output strict compact JSON with the one key sum.
       ---
       # JSON Sum Precise


       Process:
       1. Extract all integers from the duty enter.
       2. Add them.
       3. Return precisely one compact JSON object on this format:
          {"sum":NUMBER}
       4. Don't add areas, explanations, markdown, or additional keys.
   """).strip(),


   "acronym_upper": textwrap.dedent("""
       ---
       title: acronym-upper-exact
       description: Construct an uppercase acronym by taking the primary letter of every phrase.
       ---
       # Acronym Higher Precise


       Process:
       1. Determine the phrase after the colon.
       2. Take the primary letter of every phrase.
       3. Convert each letter to uppercase.
       4. Return solely the ultimate acronym, with no punctuation or rationalization.
   """).strip(),


   "pipe_unique_sorted_lower": textwrap.dedent("""
       ---
       title: pipe-unique-sorted-lower
       description: Normalize tokens to lowercase, deduplicate them, type ascending, and be a part of them with pipes.
       ---
       # Pipe Distinctive Sorted Decrease


       Process:
       1. Learn the token checklist after the colon.
       2. Break up by commas.
       3. Trim areas and lowercase each token.
       4. Take away duplicates.
       5. Kind alphabetically ascending.
       6. Be part of with "|" and return solely the ultimate string.
   """).strip(),


   "vowel_parity": textwrap.dedent("""
       ---
       title: vowel-parity-exact
       description: Depend vowels within the phrase and output ODD or EVEN solely.
       ---
       # Vowel Parity Precise


       Process:
       1. Learn the goal phrase after the colon.
       2. Depend vowels utilizing a, e, i, o, u.
       3. If the rely is odd, output ODD.
       4. If the rely is even, output EVEN.
       5. Return solely ODD or EVEN with no additional textual content.
   """).strip(),
}


PROMPT_APPENDIX = textwrap.dedent("""
## STRICT OUTPUT CONTRACT
- Output solely the ultimate reply.
- By no means clarify your reasoning.
- If a job expects JSON, return compact JSON with precise keys solely.
- When a related ability exists, observe it actually.
- Precise format is extra essential than being conversational.
""").strip()

Wir implementieren den benutzerdefinierten A-Evolve-Agenten, der die aktiven Eingabeaufforderungen, Fähigkeiten und den Speicher aus dem Arbeitsbereich liest und OpenAI verwendet, um jede Aufgabe zu lösen. Wir entwerfen den Agenten so, dass er relevante Fähigkeiten auswählt, aktuellen Speicher einfügt und Trajektorien in der vom Framework erwarteten Struktur zurückgibt. Wir definieren auch die Talent-Vorlagen und den strengen Ausgabevertrag, die als Hauptzutaten dienen, die die Evolutions-Engine hinzufügen kann, um die Leistung im Laufe der Zeit zu verbessern.

class ColabMutationEngine(EvolutionEngine):
   def __init__(self):
       self.cycle_count = 0


   def step(self, workspace: AgentWorkspace, observations, historical past, trial):
       self.cycle_count += 1


       failed_by_rule = defaultdict(checklist)
       for obs in observations:
           if not obs.suggestions.success:
               failed_by_rule(obs.job.metadata("rule")).append({
                   "task_id": obs.job.id,
                   "enter": obs.job.enter,
                   "gold": obs.job.metadata("reply"),
                   "pred": obs.trajectory.output
               })


       mutated = False
       summaries = ()


       current_prompt = workspace.read_prompt()
       if "STRICT OUTPUT CONTRACT" not in current_prompt:
           workspace.write_prompt(current_prompt.rstrip() + "nn" + PROMPT_APPENDIX + "n")
           mutated = True
           summaries.append("immediate hardened")


       existing_skill_names = {s.title for s in workspace.list_skills()}


       needed_rule_to_skill_name = {
           "json_sum": "json-sum-exact",
           "acronym_upper": "acronym-upper-exact",
           "pipe_unique_sorted_lower": "pipe-unique-sorted-lower",
           "vowel_parity": "vowel-parity-exact",
       }


       for rule, fails in failed_by_rule.objects():
           skill_name = needed_rule_to_skill_name(rule)
           if skill_name not in existing_skill_names:
               workspace.write_skill(skill_name, SKILL_TEMPLATES(rule))
               mutated = True
               summaries.append(f"added ability {skill_name}")


           workspace.add_memory({
               "content material": f"Cycle {self.cycle_count}: rule={rule} failed {len(fails)} time(s). Frequent failure sample: output formatting or process mismatch. Gold examples have to be adopted precisely.",
               "rule": rule,
               "examples": fails(:2)
           }, class="episodic")


       if not failed_by_rule:
           workspace.add_memory({
               "content material": f"Cycle {self.cycle_count}: all present coaching duties succeeded. Protect precise formatting conduct."
           }, class="episodic")


       abstract = " | ".be a part of(summaries) if summaries else "no mutation wanted"
       return StepResult(
           mutated=mutated,
           abstract=abstract,
           metadata={
               "failed_rules": checklist(failed_by_rule.keys()),
               "num_failed_rules": len(failed_by_rule),
               "cycle": self.cycle_count
           }
       )


def evaluate_split(agent, benchmark, cut up="prepare"):
   duties = benchmark.get_tasks(cut up=cut up, restrict=100)
   rows = ()
   complete = 0
   right = 0
   for job in duties:
       traj = agent.remedy(job)
       fb = benchmark.consider(job, traj)
       rows.append({
           "task_id": job.id,
           "rule": job.metadata("rule"),
           "enter": job.enter,
           "gold": job.metadata("reply"),
           "pred": traj.output,
           "rating": fb.rating,
           "success": fb.success
       })
       complete += 1
       right += int(fb.success)
   rating = right / max(complete, 1)
   return rating, rows


def print_table(rows, title, max_rows=20):
   print("n" + "=" * 110)
   print(title)
   print("=" * 110)
   proven = rows(:max_rows)
   for r in proven:
       print(f"({r('task_id')}) rule={r('rule')}")
       print(f"  enter : {r('enter')}")
       print(f"  gold  : {r('gold')}")
       print(f"  pred  : {r('pred')}")
       print(f"  rating : {r('rating')}  success={r('success')}")
       print("-" * 110)


def show_workspace(root: Path):
   print("n" + "=" * 110)
   print("EVOLVED WORKSPACE SNAPSHOT")
   print("=" * 110)
   for path in sorted(root.rglob("*")):
       rel = path.relative_to(root)
       if path.is_dir():
           print(f"(DIR ) {rel}/")
       else:
           print(f"(FILE) {rel}")


def show_skill_contents(root: Path):
   skill_files = sorted((root / "expertise").glob("*/SKILL.md"))
   print("n" + "=" * 110)
   print("SKILL FILES")
   print("=" * 110)
   if not skill_files:
       print("No ability information but.")
   for sf in skill_files:
       print(f"n--- {sf.dad or mum.title}/SKILL.md ---")
       print(sf.read_text())

Wir erstellen eine benutzerdefinierte Evolutions-Engine, die Fehler untersucht und entscheidet, wie der Arbeitsbereich verändert wird. Wir verwenden es, um die Eingabeaufforderung zu verschärfen, fehlende Fähigkeiten hinzuzufügen und das episodische Gedächtnis zu speichern, damit der Agent über Zyklen hinweg nach und nach bessere Formatierungen und aufgabenspezifisches Verhalten lernt. Wir definieren außerdem Auswertungs- und Berichtsdienstprogramme, die uns helfen, den Agenten zu bewerten, Vorhersagen zu überprüfen und den entwickelten Arbeitsbereich klar anzuzeigen.

benchmark = MiniTextBenchmark()
agent = ColabAEResolverAgent(WORKSPACE_ROOT, mannequin=OPENAI_MODEL)
engine = ColabMutationEngine()


baseline_train_score, baseline_train_rows = evaluate_split(agent, benchmark, cut up="prepare")
baseline_holdout_score, baseline_holdout_rows = evaluate_split(agent, benchmark, cut up="holdout")


print(f"Baseline prepare rating   : {baseline_train_score:.3f}")
print(f"Baseline holdout rating : {baseline_holdout_score:.3f}")


print_table(baseline_train_rows, "BASELINE TRAIN RESULTS")
print_table(baseline_holdout_rows, "BASELINE HOLDOUT RESULTS")


config = ae.EvolveConfig(
   batch_size=8,
   max_cycles=4,
   egl_window=2
)


evolver = ae.Evolver(
   agent=agent,
   benchmark=benchmark,
   config=config,
   engine=engine
)


consequence = evolver.run(cycles=4)


print("n" + "=" * 110)
print("A-EVOLVE RUN SUMMARY")
print("=" * 110)
print(f"Cycles accomplished : {consequence.cycles_completed}")
print(f"Remaining prepare rating: {consequence.final_score:.3f}")
print(f"Rating historical past    : {consequence.score_history}")
print(f"Converged        : {consequence.converged}")


agent.reload_from_fs()
final_train_score, final_train_rows = evaluate_split(agent, benchmark, cut up="prepare")
final_holdout_score, final_holdout_rows = evaluate_split(agent, benchmark, cut up="holdout")


print(f"nFinal prepare rating   : {final_train_score:.3f}")
print(f"Remaining holdout rating : {final_holdout_score:.3f}")


print_table(final_train_rows, "FINAL TRAIN RESULTS")
print_table(final_holdout_rows, "FINAL HOLDOUT RESULTS")


show_workspace(WORKSPACE_ROOT)
show_skill_contents(WORKSPACE_ROOT)


print("n" + "=" * 110)
print("FINAL SYSTEM PROMPT")
print("=" * 110)
print((WORKSPACE_ROOT / "prompts" / "system.md").read_text())


episodic_path = WORKSPACE_ROOT / "reminiscence" / "episodic.jsonl"
if episodic_path.exists():
   print("n" + "=" * 110)
   print("RECENT EPISODIC MEMORY")
   print("=" * 110)
   strains = episodic_path.read_text().strip().splitlines()
   for line in strains(-10:):
       print(line)


plt.determine(figsize=(8, 4))
plt.plot(vary(1, len(consequence.score_history) + 1), consequence.score_history, marker="o")
plt.xlabel("Evolution cycle")
plt.ylabel("Prepare rating")
plt.title("A-Evolve rating historical past")
plt.grid(True)
plt.present()


print("n" + "=" * 110)
print("COMPARISON")
print("=" * 110)
print(f"Prepare   : {baseline_train_score:.3f} -> {final_train_score:.3f}")
print(f"Holdout : {baseline_holdout_score:.3f} -> {final_holdout_score:.3f}")


improved_rules = ()
for earlier than, after in zip(sorted(baseline_train_rows, key=lambda x: x("task_id")), sorted(final_train_rows, key=lambda x: x("task_id"))):
   if (not earlier than("success")) and after("success"):
       improved_rules.append(after("rule"))


print(f"Improved prepare circumstances by rule: {dict(Counter(improved_rules))}")


print("nDone. This pocket book used the true A-Evolve framework and demonstrated:")
print("1) a sound agent workspace")
print("2) a BaseAgent subclass")
print("3) a BenchmarkAdapter subclass")
print("4) an EvolutionEngine subclass")
print("5) immediate / ability / reminiscence mutations throughout A-Evolve cycles")

Wir stellen alles zusammen und führen den gesamten A-Evolve-Kreislauf von der Basisbewertung bis zur Publish-Evolution-Analyse durch. Wir messen den Agenten vor dem Coaching, führen mehrere Entwicklungszyklen durch, laden den Arbeitsbereich neu und vergleichen dann die endgültige Trainings- und Holdout-Leistung, um zu sehen, was sich verbessert. Wir untersuchen auch die entwickelten Eingabeaufforderungen, Fähigkeiten, das Gedächtnis und den Bewertungsverlauf, wodurch wir klar beobachten können, wie das Framework den Agenten Schritt für Schritt transformiert.

Zusammenfassend lässt sich sagen, dass wir erfolgreich einen vollständigen A-Evolve-Workflow aufgebaut und ausgeführt haben, anstatt das Repository nur auf oberflächlicher Ebene zu inspizieren. Wir haben einen gültigen Arbeitsbereich erstellt, einen benutzerdefinierten Agenten angeschlossen, ihn anhand strukturierter Aufgaben verglichen und dann sein Verhalten weiterentwickelt, indem wir Eingabeaufforderungen geändert, Fähigkeiten hinzugefügt und Speicher über Zyklen hinweg gespeichert haben. Außerdem haben wir gesehen, wie das Design von A-Evolve es uns ermöglicht, die Verbesserung von Wirkstoffen als einen wiederholbaren technischen Prozess zu behandeln, bei dem wir die Basisleistung messen, kontrollierte Mutationen anwenden und beobachten können, wie das System mit der Zeit genauer wird.


Schauen Sie sich das an Das vollständige Coding-Notizbuch finden Sie hier. Sie können uns auch gerne weiter folgen Twitter und vergessen Sie nicht, bei uns mitzumachen 120.000+ ML SubReddit und Abonnieren Unser Publication. Warten! Bist du im Telegram? Jetzt können Sie uns auch per Telegram kontaktieren.


Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert