aidn commited on
Commit
10aee01
·
verified ·
1 Parent(s): 256d64b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +188 -118
index.html CHANGED
@@ -8,7 +8,7 @@
8
  <!-- Tailwind CSS -->
9
  <script src="https://cdn.tailwindcss.com"></script>
10
 
11
- <!-- Highlight.js for Code Formatting (Atom One Dark is close to HF's dark code blocks) -->
12
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
13
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
14
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>
@@ -16,7 +16,7 @@
16
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
17
 
18
  <!-- Google Fonts (Inter & Source Code Pro for HF feel) -->
19
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Source+Code+Pro:wght@400;500&display=swap" rel="stylesheet">
20
 
21
  <script>
22
  tailwind.config = {
@@ -47,19 +47,19 @@
47
 
48
  <style>
49
  body { font-family: 'Inter', sans-serif; background-color: #ffffff; color: #111827; }
50
- pre code { font-family: 'Source Code Pro', monospace; border-radius: 0.75rem; font-size: 0.875rem; padding: 1.25rem; }
51
- .prose h2 { margin-top: 3rem; margin-bottom: 1.25rem; font-weight: 700; font-size: 1.75rem; color: #111827; border-bottom: 1px solid #E5E7EB; padding-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
52
- .prose h3 { margin-top: 2rem; margin-bottom: 1rem; font-weight: 600; font-size: 1.25rem; color: #374151; }
53
  .prose p { margin-bottom: 1.25rem; line-height: 1.8; color: #4B5563; }
54
  .prose table { width: 100%; border-collapse: collapse; margin-bottom: 2rem; border-radius: 0.5rem; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
55
  .prose th, .prose td { border: 1px solid #E5E7EB; padding: 1rem; text-align: left; font-size: 0.95rem; }
56
  .prose th { background-color: #F9FAFB; font-weight: 600; color: #111827; }
57
 
58
  /* Tooltip / Copy Button */
59
- .copy-btn { position: absolute; top: 0.75rem; right: 0.75rem; background: rgba(255,255,255,0.1); color: #D1D5DB; border: 1px solid rgba(255,255,255,0.2); padding: 0.25rem 0.75rem; border-radius: 0.375rem; cursor: pointer; font-size: 0.75rem; transition: all 0.2s; }
60
  .copy-btn:hover { background: rgba(255,255,255,0.2); color: #fff; }
61
- .code-wrapper { position: relative; margin-bottom: 2rem; border-radius: 0.75rem; background: #282c34; }
62
- .file-label { position: absolute; top: -12px; left: 16px; background: #FFD21E; color: #111827; padding: 0.1rem 0.75rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; z-index: 10; font-family: 'Source Code Pro', monospace; border: 2px solid #fff; }
63
 
64
  /* Custom Scrollbar for Sidebar */
65
  #sidebar::-webkit-scrollbar { width: 6px; }
@@ -107,9 +107,9 @@
107
  <div class="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2 ml-3 mt-6">Orchestrierung & Code</div>
108
  <ul class="space-y-1 text-sm font-medium">
109
  <li><a href="#orchestration" class="block py-2 px-3 text-gray-600 rounded-lg hover:bg-gray-200 hover:text-gray-900 transition">7. Routing & Tool-Calling</a></li>
110
- <li><a href="#repo" class="flex items-center gap-2 py-2 px-3 bg-hfYellow/20 text-yellow-800 rounded-lg hover:bg-hfYellow/30 transition">
111
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
112
- 8. Repositorystruktur & main.py
113
  </a></li>
114
  </ul>
115
  </div>
@@ -125,42 +125,43 @@
125
  <span class="text-4xl">🥘</span>
126
  <h1 class="text-3xl font-bold text-gray-900 m-0">Architektur eines Kulinarischen MAS</h1>
127
  </div>
128
- <p class="text-gray-700 text-lg leading-relaxed m-0">Ein Konzept zur Orchestrierung von Multi-Agenten-Systemen (MAS) für <strong>"The Infinite Cookbook"</strong>. Wir zerlegen komplexe Aufgaben in spezialisierte Haystack 2.0 Pipelines und verbinden sie über die Hugging Face Infrastruktur (Open-Source LLMs) zu einem autonomen System.</p>
129
  </div>
130
 
131
  <section id="intro">
132
  <h2><span>🏗️</span> 1. Das Konzept: Haystack 2.0</h2>
133
- <p>Der Paradigmenwechsel: Ein einzelnes LLM scheitert oft an komplexen, mehrstufigen Aufgaben. Unser Konzept setzt auf <strong>Komponenten und Pipelines als dynamische Rechengraphen</strong>. Ein Agent in diesem Ökosystem ist eine autonome Einheit (z.B. ein spezialisiertes LLM + Tools), die Aufgaben plant, Werkzeuge auswählt und Strategien anpasst.</p>
 
134
  </section>
135
 
136
  <section id="hf-infra">
137
  <h2><span>🤗</span> 2. Hugging Face Inference Provider</h2>
138
- <p>Anstatt auf proprietäre Blackbox-Modelle zu setzen, nutzt dieses Konzept den Hugging Face Hub. Die <code>HuggingFaceAPIChatGenerator</code>-Komponente von Haystack ermöglicht nahtloses Wechseln zwischen Providern:</p>
139
 
140
  <div class="overflow-x-auto">
141
  <table>
142
  <thead>
143
  <tr>
144
- <th>Infrastruktur</th>
145
  <th>Charakteristika</th>
146
- <th>Modell-Beispiel im MAS</th>
147
  </tr>
148
  </thead>
149
  <tbody>
150
  <tr>
151
- <td><strong>Serverless API</strong></td>
152
- <td>Kostenlos, für Prototyping</td>
153
- <td class="font-mono text-sm">Qwen/Qwen2.5-72B-Instruct</td>
154
  </tr>
155
  <tr>
156
  <td><strong>Inference Endpoints</strong></td>
157
- <td>Dediziert, garantierte Latenz</td>
158
- <td class="font-mono text-sm">black-forest-labs/FLUX.1-schnell</td>
159
  </tr>
160
  <tr>
161
- <td><strong>TGI (Text Generation)</strong></td>
162
- <td>Unterstützt JSON-Guiding</td>
163
- <td class="font-mono text-sm">mistralai/Mistral-7B-Instruct</td>
164
  </tr>
165
  </tbody>
166
  </table>
@@ -169,65 +170,48 @@
169
 
170
  <section id="agent1">
171
  <h2><span>🔍</span> 3. Agent 1: Forschung & Suche</h2>
172
- <p>Dieser Sub-Agent kapselt die Recherche. Er nutzt Web-Suchen, lädt HTML-Inhalte herunter, bereinigt sie und rankt sie. Das Ergebnis ist eine fokussierte Wissensbasis.</p>
173
- <div class="code-wrapper mt-4">
 
 
174
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
175
  <pre><code class="language-python">from haystack import Pipeline
176
  from haystack.components.websearch import SerperDevWebSearch
177
- # ... imports
178
- research_pipe = Pipeline()
179
- research_pipe.add_component("search", SerperDevWebSearch(api_key="KEY"))
180
- research_pipe.add_component("ranker", TransformersSimilarityRanker())
181
- # ... verbindungen</code></pre>
182
- </div>
183
- </section>
184
 
185
- <section id="agent2">
186
- <h2><span>📋</span> 4. Agent 2: Struktur & Pydantic</h2>
187
- <p>Um die unstrukturierten Forschungsnotizen maschinenlesbar zu machen, zwingen wir das LLM mittels <strong>Pydantic</strong> in ein striktes JSON-Schema. Das eliminiert Halluzinationen in der Datenstruktur.</p>
188
- </section>
189
 
190
- <section id="agent3">
191
- <h2><span>🎨</span> 5. Agent 3: Visionär (Bildgen.)</h2>
192
- <p>Da Sprachmodelle keine Bilder malen können, bauen wir eine eigene Custom Component in Haystack (<code>@component</code>), die via <code>diffusers</code> Bibliothek ein Stable Diffusion oder FLUX Modell ansteuert und als Base64-String zurückgibt.</p>
193
- </section>
 
 
 
194
 
195
- <section id="agent4">
196
- <h2><span>💻</span> 6. Agent 4: Meta-Aggregator (HTML)</h2>
197
- <p>Dieser Agent nutzt Jinja2-Templates, um die JSON-Daten (aus Agent 2) und den Base64-Bild-String (aus Agent 3) in eine fertige HTML-Rezeptkarte zu gießen.</p>
198
- </section>
199
 
200
- <section id="orchestration">
201
- <h2><span>🚦</span> 7. Orchestrierung: Agent-as-a-Tool</h2>
202
- <p>Die Magie passiert im Koordinator-Agenten. Anstatt alle Pipelines händisch zu verketten, packen wir jede Pipeline in ein Haystack <code>Tool</code>-Objekt. Ein übergeordnetes LLM entscheidet dann dynamisch, welches Tool aufgerufen werden muss.</p>
203
  </section>
204
 
205
- <!-- KAPITEL 8: REPOSITORY UND CODE -->
206
- <section id="repo">
207
- <h2 class="bg-hfYellow/20 -mx-6 px-6 py-4 rounded-xl text-yellow-900 border-l-4 border-hfYellow">
208
- <span>📁</span> 8. Die Code-Struktur (Vom Konzept zur Realität)
209
- </h2>
210
- <p>Ein Monolith (alles in einem Skript) führt bei MAS unweigerlich ins Chaos. Eine saubere Repository-Struktur spiegelt die Modularität des Konzepts wider. Hier siehst du, wie die konkreten Dateien in einem echten Projekt aussehen.</p>
211
 
212
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-4 mb-8 font-mono text-sm text-gray-700 leading-relaxed shadow-sm">
213
- infinite-cookbook/<br>
214
- ├── <span class="font-bold text-gray-900">schemas/</span><br>
215
- │ └── <a href="#file-schema" class="text-blue-600 hover:underline">recipe.py</a> <span class="text-gray-400 italic"># Pydantic Modelle</span><br>
216
- ├── <span class="font-bold text-gray-900">agents/</span><br>
217
- │ └── <a href="#file-researcher" class="text-blue-600 hover:underline">researcher.py</a> <span class="text-gray-400 italic"># Pipeline Definitionen</span><br>
218
- ├── <span class="font-bold text-gray-900">tools/</span><br>
219
- │ └── <a href="#file-tools" class="text-blue-600 hover:underline">agent_tools.py</a> <span class="text-gray-400 italic"># Wrapper: Pipeline -> Tool</span><br>
220
- └── <a href="#file-main" class="text-blue-600 hover:underline font-bold">main.py</a> <span class="text-gray-400 italic"># Orchestrierungs-Loop</span>
221
- </div>
222
-
223
- <h3 id="file-schema" class="flex items-center gap-2 mt-10"><svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path></svg> 1. Datenschemata</h3>
224
- <p>Wir definieren zentral, wie unser Endprodukt auszusehen hat.</p>
225
- <div class="code-wrapper mt-4">
226
  <div class="file-label">schemas/recipe.py</div>
227
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
228
  <pre><code class="language-python">from pydantic import BaseModel
229
- from typing import List, Literal
230
 
 
231
  class Ingredient(BaseModel):
232
  name: str
233
  amount: float
@@ -238,68 +222,151 @@ class RecipeStructure(BaseModel):
238
  servings: int
239
  ingredients: List[Ingredient]
240
  instructions: List[str]
241
- difficulty: Literal["Einfach", "Mittel", "Schwer"]</code></pre>
 
 
 
 
 
 
 
242
  </div>
 
243
 
244
- <h3 id="file-researcher" class="flex items-center gap-2 mt-10"><svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path></svg> 2. Pipeline Module</h3>
245
- <p>Anstatt Pipelines global zu instanziieren, verpacken wir sie in Funktionen (Factory-Pattern). So bleiben sie testbar.</p>
246
- <div class="code-wrapper mt-4">
247
- <div class="file-label">agents/researcher.py</div>
 
 
248
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
249
- <pre><code class="language-python">from haystack import Pipeline
250
- from haystack.components.websearch import SerperDevWebSearch
251
- from haystack.components.fetchers import LinkContentFetcher
252
- from haystack.components.converters import HTMLToDocument
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
- def build_research_pipeline() -> Pipeline:
255
- """Baut den Graphen für die Web-Recherche."""
256
- pipe = Pipeline()
 
 
 
 
 
 
 
257
 
258
- # Komponenten hinzufügen
259
- pipe.add_component("search", SerperDevWebSearch())
260
- pipe.add_component("fetcher", LinkContentFetcher())
261
- pipe.add_component("html_converter", HTMLToDocument())
262
 
263
- # Kanten (Edges) verbinden
264
- pipe.connect("search.links", "fetcher.urls")
265
- pipe.connect("fetcher.streams", "html_converter.sources")
266
 
267
- return pipe</code></pre>
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  </div>
 
269
 
270
- <h3 id="file-tools" class="flex items-center gap-2 mt-10"><svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg> 3. Die Werkzeugkiste (Tool-Wrapper)</h3>
271
- <p>Hier importieren wir die Pipelines und machen sie für das Koordinator-LLM "lesbar", indem wir sie mit Beschreibungen und Schemata versehen.</p>
272
- <div class="code-wrapper mt-4">
 
 
 
 
273
  <div class="file-label">tools/agent_tools.py</div>
274
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
275
  <pre><code class="language-python">from haystack.tools import Tool
 
276
  from agents.researcher import build_research_pipeline
277
- # from agents.structurer import build_structuring_pipeline
278
 
279
- # 1. Pipelines instanziieren
280
  research_pipe = build_research_pipeline()
281
- # structurer_pipe = build_structuring_pipeline()
282
 
283
- # 2. In Tools kapseln
284
  research_tool = Tool(
285
  name="research_tool",
286
- description="Nutze dieses Tool ZUERST. Durchsucht das Web nach authentischen Rezept-Infos.",
287
- parameters={
288
- "type": "object",
289
- "properties": {
290
- "query": {"type": "string", "description": "Der Suchbegriff, z.B. 'original Pad Thai'"}
291
- },
292
- "required": ["query"]
293
- },
294
  function=research_pipe.run
295
  )
296
 
297
- # Tool-Liste für den Haupt-Agenten exportieren
298
- cookbook_tools = [research_tool] # + structurer_tool, image_tool, html_tool</code></pre>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  </div>
 
300
 
301
- <h3 id="file-main" class="flex items-center gap-2 mt-10"><svg class="w-5 h-5 text-hfYellow" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg> 4. Das Herzstück: main.py</h3>
302
- <p>Die <code>main.py</code> ist nun unglaublich aufgeräumt. Sie initialisiert lediglich das Haupt-LLM (über Hugging Face), importiert die fertige Werkzeugkiste und startet die Interaktions-Schleife.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  <div class="code-wrapper mt-4">
304
  <div class="file-label">main.py</div>
305
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
@@ -309,11 +376,11 @@ from haystack.components.generators.chat import HuggingFaceAPIChatGenerator
309
  from haystack.components.tools import ToolInvoker
310
  from haystack.dataclasses import ChatMessage
311
 
312
- # Unsere sauberen, modularen Imports!
313
  from tools.agent_tools import cookbook_tools
314
 
315
  def main():
316
- # 1. Der Koordinator: Ein starkes Modell, das Tool-Calling beherrscht
317
  llm = HuggingFaceAPIChatGenerator(
318
  api_type="serverless_inference_api",
319
  model="Qwen/Qwen2.5-72B-Instruct",
@@ -323,12 +390,12 @@ def main():
323
  # 2. Der Invoker: Führt die vom LLM gewählten Tools aus
324
  invoker = ToolInvoker(tools=cookbook_tools)
325
 
326
- # 3. Der Routing-Graph
327
  coordinator = Pipeline()
328
  coordinator.add_component("llm", llm)
329
  coordinator.add_component("invoker", invoker)
330
 
331
- # Zyklische Verbindung für iteratives Arbeiten
332
  coordinator.connect("llm.replies", "invoker.messages")
333
  coordinator.connect("invoker.tool_messages", "llm.messages")
334
 
@@ -338,11 +405,11 @@ def main():
338
 
339
  print(f"🤖 Koordinator startet Aufgabe: {user_prompt}")
340
 
341
- # Run Loop (Vereinfachte Ausführung)
 
 
342
  result = coordinator.run({"llm": {"messages": messages}})
343
 
344
- # Im echten MAS läuft dies in einer Schleife (ConditionalRouter),
345
- # bis das LLM entscheidet: "Ich bin fertig und nutze kein Tool mehr."
346
  print("Fertiges Ergebnis:", result["llm"]["replies"][0].text)
347
 
348
  if __name__ == "__main__":
@@ -353,7 +420,7 @@ if __name__ == "__main__":
353
  <span class="text-2xl">💡</span>
354
  <div>
355
  <strong class="text-gray-900 block mb-1">Die Architektur-Philosophie:</strong>
356
- Diese Aufteilung erlaubt es dir, die <code>researcher.py</code> komplett umzuschreiben oder das Modell in <code>main.py</code> auszutauschen, ohne dass du Angst haben musst, den Code des Bild-Generators kaputtzumachen. Das ist die wahre Stärke von Haystack 2.0 in Kombination mit einem modularen Setup!
357
  </div>
358
  </div>
359
 
@@ -379,7 +446,7 @@ if __name__ == "__main__":
379
  sidebar.classList.toggle('hidden');
380
  });
381
 
382
- // Smooth scroll adjustment for fixed header (mobile)
383
  document.querySelectorAll('a[href^="#"]').forEach(anchor => {
384
  anchor.addEventListener('click', function (e) {
385
  e.preventDefault();
@@ -392,8 +459,11 @@ if __name__ == "__main__":
392
  a.classList.remove('bg-hfYellow/20', 'text-yellow-800', 'font-semibold');
393
  a.classList.add('text-gray-600');
394
  });
395
- this.classList.remove('text-gray-600');
396
- this.classList.add('bg-hfYellow/20', 'text-yellow-800', 'font-semibold');
 
 
 
397
 
398
  document.querySelector(this.getAttribute('href')).scrollIntoView({
399
  behavior: 'smooth'
 
8
  <!-- Tailwind CSS -->
9
  <script src="https://cdn.tailwindcss.com"></script>
10
 
11
+ <!-- Highlight.js for Code Formatting -->
12
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
13
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
14
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>
 
16
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
17
 
18
  <!-- Google Fonts (Inter & Source Code Pro for HF feel) -->
19
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Source+Code+Pro:wght@400;500;600&display=swap" rel="stylesheet">
20
 
21
  <script>
22
  tailwind.config = {
 
47
 
48
  <style>
49
  body { font-family: 'Inter', sans-serif; background-color: #ffffff; color: #111827; }
50
+ pre code { font-family: 'Source Code Pro', monospace; border-radius: 0.75rem; font-size: 0.875rem; padding: 1.5rem 1.25rem 1.25rem 1.25rem; }
51
+ .prose h2 { margin-top: 3.5rem; margin-bottom: 1.25rem; font-weight: 700; font-size: 1.75rem; color: #111827; border-bottom: 1px solid #E5E7EB; padding-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
52
+ .prose h3 { margin-top: 2.5rem; margin-bottom: 1rem; font-weight: 600; font-size: 1.25rem; color: #374151; }
53
  .prose p { margin-bottom: 1.25rem; line-height: 1.8; color: #4B5563; }
54
  .prose table { width: 100%; border-collapse: collapse; margin-bottom: 2rem; border-radius: 0.5rem; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
55
  .prose th, .prose td { border: 1px solid #E5E7EB; padding: 1rem; text-align: left; font-size: 0.95rem; }
56
  .prose th { background-color: #F9FAFB; font-weight: 600; color: #111827; }
57
 
58
  /* Tooltip / Copy Button */
59
+ .copy-btn { position: absolute; top: 0.75rem; right: 0.75rem; background: rgba(255,255,255,0.1); color: #D1D5DB; border: 1px solid rgba(255,255,255,0.2); padding: 0.25rem 0.75rem; border-radius: 0.375rem; cursor: pointer; font-size: 0.75rem; transition: all 0.2s; z-index: 20; }
60
  .copy-btn:hover { background: rgba(255,255,255,0.2); color: #fff; }
61
+ .code-wrapper { position: relative; margin-top: 1.5rem; margin-bottom: 2rem; border-radius: 0.75rem; background: #282c34; }
62
+ .file-label { position: absolute; top: -14px; left: 16px; background: #FFD21E; color: #111827; padding: 0.15rem 0.75rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 700; z-index: 10; font-family: 'Source Code Pro', monospace; border: 2px solid #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
63
 
64
  /* Custom Scrollbar for Sidebar */
65
  #sidebar::-webkit-scrollbar { width: 6px; }
 
107
  <div class="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2 ml-3 mt-6">Orchestrierung & Code</div>
108
  <ul class="space-y-1 text-sm font-medium">
109
  <li><a href="#orchestration" class="block py-2 px-3 text-gray-600 rounded-lg hover:bg-gray-200 hover:text-gray-900 transition">7. Routing & Tool-Calling</a></li>
110
+ <li><a href="#repo" class="flex items-center gap-2 py-2 px-3 bg-hfYellow/20 text-yellow-900 rounded-lg hover:bg-hfYellow/30 transition">
111
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
112
+ 8. Repositorystruktur
113
  </a></li>
114
  </ul>
115
  </div>
 
125
  <span class="text-4xl">🥘</span>
126
  <h1 class="text-3xl font-bold text-gray-900 m-0">Architektur eines Kulinarischen MAS</h1>
127
  </div>
128
+ <p class="text-gray-700 text-lg leading-relaxed m-0">Ein Deep-Dive in die Orchestrierung von Multi-Agenten-Systemen (MAS) für <strong>"The Infinite Cookbook"</strong>. Wir zerlegen komplexe Aufgaben (Recherche, Strukturierung, Bildgenerierung, Layout) in spezialisierte Haystack 2.0 Pipelines und verbinden sie über Hugging Face Open-Source LLMs zu einem autonomen System.</p>
129
  </div>
130
 
131
  <section id="intro">
132
  <h2><span>🏗️</span> 1. Das Konzept: Haystack 2.0</h2>
133
+ <p>Die Evolution der KI verlangt nach neuen Architekturen. Der Übergang von Haystack 1.x zu 2.0 markiert einen Paradigmenwechsel: Frühere Versionen waren auf lineare Ketten ausgelegt, Haystack 2.0 führt <strong>Komponenten und Pipelines als dynamische Rechengraphen</strong> ein.</p>
134
+ <p>Diese Graphen unterstützen Kontrollflüsse, Schleifen und präzises Routing. Ein Agent in diesem Ökosystem ist weit mehr als ein Chatbot; er ist ein System, das ein LLM als Steuerungsorgan nutzt, um Aufgaben zu planen und an spezialisierte Sub-Pipelines (andere Agenten) zu delegieren. Typprüfung an den Ein- und Ausgabesockets sichert dabei die Stabilität vor der Laufzeit.</p>
135
  </section>
136
 
137
  <section id="hf-infra">
138
  <h2><span>🤗</span> 2. Hugging Face Inference Provider</h2>
139
+ <p>Hugging Face ist der zentrale Marktplatz für Open-Source-Intelligenz. Im Juli 2025 stellte die Inference API auf <code>chat_completion</code>-Endpunkte um. Haystack bindet diese Modelle über die <code>HuggingFaceAPIChatGenerator</code>-Komponente ein. Durch dynamische Suffixe wie <code>:fastest</code> oder Provider-Wahl können wir Lasten optimieren:</p>
140
 
141
  <div class="overflow-x-auto">
142
  <table>
143
  <thead>
144
  <tr>
145
+ <th>Infrastruktur-Option</th>
146
  <th>Charakteristika</th>
147
+ <th>Anwendungsfall im MAS</th>
148
  </tr>
149
  </thead>
150
  <tbody>
151
  <tr>
152
+ <td><strong>Serverless Inference API</strong></td>
153
+ <td>Kostenlos/Rate-limited, schnell</td>
154
+ <td>Prototyping und einfache Zusammenfassungen (z.B. Qwen 72B).</td>
155
  </tr>
156
  <tr>
157
  <td><strong>Inference Endpoints</strong></td>
158
+ <td>Dedizierte Instanzen, /h Abrechnung</td>
159
+ <td>Produktion, garantierte Latenz, Bildgenerierung (SDXL / FLUX).</td>
160
  </tr>
161
  <tr>
162
+ <td><strong>Text Generation Inference (TGI)</strong></td>
163
+ <td>Optimiertes Serving, JSON-Guiding</td>
164
+ <td>Komplexe Datenextraktion mit strikter Schema-Einhaltung.</td>
165
  </tr>
166
  </tbody>
167
  </table>
 
170
 
171
  <section id="agent1">
172
  <h2><span>🔍</span> 3. Agent 1: Forschung & Suche</h2>
173
+ <p>Die erste Phase ist die <em>Deep Research Phase</em>. Dieser Agent durchsucht das Web iterativ nach authentischen Rezepten, regionalen Varianten und historischen Hintergründen. Er nutzt Tools, um Links zu besuchen, HTML zu bereinigen und die Ergebnisse nach Relevanz (Context Optimization) zu ranken, bevor sie ans LLM gehen.</p>
174
+
175
+ <div class="code-wrapper">
176
+ <div class="file-label">agents/researcher.py</div>
177
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
178
  <pre><code class="language-python">from haystack import Pipeline
179
  from haystack.components.websearch import SerperDevWebSearch
180
+ from haystack.components.fetchers import LinkContentFetcher
181
+ from haystack.components.converters import HTMLToDocument
182
+ from haystack.components.rankers import TransformersSimilarityRanker
 
 
 
 
183
 
184
+ def build_research_pipeline() -> Pipeline:
185
+ pipe = Pipeline()
 
 
186
 
187
+ # Komponenten initialisieren
188
+ pipe.add_component("search", SerperDevWebSearch(api_key="DEIN_API_KEY"))
189
+ pipe.add_component("fetcher", LinkContentFetcher())
190
+ pipe.add_component("html_converter", HTMLToDocument())
191
+
192
+ # Der Ranker sortiert Dokumente nach Relevanz zur Suchanfrage aus
193
+ pipe.add_component("ranker", TransformersSimilarityRanker(model="cross-encoder/ms-marco-MiniLM-L-6-v2"))
194
 
195
+ # Den gerichteten Graphen aufbauen
196
+ pipe.connect("search.links", "fetcher.urls")
197
+ pipe.connect("fetcher.streams", "html_converter.sources")
198
+ pipe.connect("html_converter.documents", "ranker.documents")
199
 
200
+ return pipe</code></pre>
201
+ </div>
 
202
  </section>
203
 
204
+ <section id="agent2">
205
+ <h2><span>📋</span> 4. Agent 2: Struktur & Pydantic</h2>
206
+ <p>Der Zusammenfassungs-Agent wandelt die unstrukturierten Forschungsnotizen in ein präzises, maschinenlesbares Rezept um. Das ist kritisch, da Inkonsistenzen das HTML-Layout gefährden. Haystack 2.0 erzwingt strukturierte Ausgaben über <strong>Pydantic-Modelle</strong> (besonders mächtig in Kombination mit Hugging Face TGI-Instanzen).</p>
 
 
 
207
 
208
+ <div class="code-wrapper">
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  <div class="file-label">schemas/recipe.py</div>
210
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
211
  <pre><code class="language-python">from pydantic import BaseModel
212
+ from typing import List, Dict, Literal
213
 
214
+ # Strikte Typisierung eliminiert Halluzinationen in der Struktur
215
  class Ingredient(BaseModel):
216
  name: str
217
  amount: float
 
222
  servings: int
223
  ingredients: List[Ingredient]
224
  instructions: List[str]
225
+ nutrients: Dict[str, float]
226
+ difficulty: Literal["Einfach", "Mittel", "Schwer"]
227
+
228
+ # Nutzungshinweis für die Pipeline:
229
+ # generator = HuggingFaceAPIChatGenerator(
230
+ # api_type="text_generation_inference",
231
+ # generation_kwargs={"response_format": RecipeStructure.schema_json()}
232
+ # )</code></pre>
233
  </div>
234
+ </section>
235
 
236
+ <section id="agent3">
237
+ <h2><span>🎨</span> 5. Agent 3: Visionär (Bildgenerierung)</h2>
238
+ <p>Ein Kochbuch braucht Ästhetik. Da Sprachmodelle keinen Text in Bilder konvertieren, implementieren wir eine <strong>benutzerdefinierte Haystack-Komponente</strong>. Diese nimmt den Rezepttitel auf, optimiert den Prompt ("Professionelle Food-Fotografie, Makro...") und steuert via <code>diffusers</code> ein Modell wie Stable Diffusion XL oder FLUX an.</p>
239
+
240
+ <div class="code-wrapper">
241
+ <div class="file-label">components/image_generator.py</div>
242
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
243
+ <pre><code class="language-python">from haystack import component
244
+ from haystack.dataclasses import ImageContent
245
+ # import diffusers ...
246
+
247
+ @component
248
+ class StableDiffusionGenerator:
249
+ def __init__(self, model_id="stabilityai/stable-diffusion-xl-base-1.0"):
250
+ self.model_id = model_id
251
+ # Initialisierung z.B. Pipeline Laden inkl. FP16 Optimierung
252
+
253
+ # Definition des Output-Sockets für die Validierung vor der Laufzeit
254
+ @component.output_types(image=ImageContent)
255
+ def run(self, prompt: str):
256
+ # image = self.pipe(prompt).images[0]
257
+ # base64_str = convert_to_base64(image)
258
+
259
+ # Rückgabe als Haystack 2.0 Multimodal Objekt
260
+ return {"image": ImageContent.from_base64(base64_str)}</code></pre>
261
+ </div>
262
+ </section>
263
 
264
+ <section id="agent4">
265
+ <h2><span>💻</span> 6. Agent 4: Meta-Aggregator (HTML)</h2>
266
+ <p>Der letzte Agent orchestriert die Präsentation. Er empfängt das strukturierte Rezept (als Dictionary/JSON) und das generierte Bild (als Base64) und verpackt beides über <strong>Jinja2-Templating</strong>.</p>
267
+
268
+ <div class="code-wrapper">
269
+ <div class="file-label">templates/recipe_card.html</div>
270
+ <button class="copy-btn" onclick="copyCode(this)">Copy</button>
271
+ <pre><code class="language-xml">&lt;!-- Das Template wird vom HTML-Agenten mit Daten befüllt --&gt;
272
+ &lt;div class="recipe-card"&gt;
273
+ &lt;h1&gt;{{ recipe_title }}&lt;/h1&gt;
274
 
275
+ &lt;!-- Base64 Einbettung erspart externe Bild-Hostings --&gt;
276
+ &lt;img src="data:image/png;base64,{{ image_base64 }}" alt="{{ recipe_title }}"&gt;
 
 
277
 
278
+ &lt;div class="meta"&gt;
279
+ &lt;span&gt;Schwierigkeit: {{ difficulty }}&lt;/span&gt;
280
+ &lt;/div&gt;
281
 
282
+ &lt;h3&gt;Zutaten&lt;/h3&gt;
283
+ &lt;ul&gt;
284
+ {% for ingredient in ingredients %}
285
+ &lt;li&gt;{{ ingredient.amount }} {{ ingredient.unit }} {{ ingredient.name}}&lt;/li&gt;
286
+ {% endfor %}
287
+ &lt;/ul&gt;
288
+
289
+ &lt;h3&gt;Zubereitung&lt;/h3&gt;
290
+ &lt;ol&gt;
291
+ {% for step in instructions %}
292
+ &lt;li&gt;{{ step }}&lt;/li&gt;
293
+ {% endfor %}
294
+ &lt;/ol&gt;
295
+ &lt;/div&gt;</code></pre>
296
  </div>
297
+ </section>
298
 
299
+ <section id="orchestration">
300
+ <h2><span>🚦</span> 7. Orchestrierung & Fehlerbehandlung</h2>
301
+ <p>Um diese Agenten zu vereinen, nutzen wir den <strong>"Agent-as-a-Tool"</strong>-Ansatz. Ein Koordinator-Agent kapselt die Pipelines in Werkzeugen. So kann das Haupt-LLM dynamisch entscheiden, wann es recherchiert und wann es Bilder generiert.</p>
302
+
303
+ <p>Für Robustheit sorgt der <code>ConditionalRouter</code>. Liefert ein Tool einen Fehler (z.B. keine Suchergebnisse), leitet der Router den Datenfluss um, sodass das LLM seinen Such-Prompt anpassen kann, anstatt abzustürzen.</p>
304
+
305
+ <div class="code-wrapper">
306
  <div class="file-label">tools/agent_tools.py</div>
307
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
308
  <pre><code class="language-python">from haystack.tools import Tool
309
+ from haystack.components.routers import ConditionalRouter
310
  from agents.researcher import build_research_pipeline
 
311
 
312
+ # Pipeline laden
313
  research_pipe = build_research_pipeline()
 
314
 
315
+ # Pipeline als aufrufbares Werkzeug für das LLM verpacken
316
  research_tool = Tool(
317
  name="research_tool",
318
+ description="Durchsucht das Web nach authentischen Rezepten.",
319
+ parameters={"query": {"type": "string"}},
 
 
 
 
 
 
320
  function=research_pipe.run
321
  )
322
 
323
+ # Fehlerbehandlung: Ein Router, der den Pfad basierend auf Tool-Erfolg wählt
324
+ routes = [
325
+ {
326
+ "condition": "{{ 'error' in tool_result.text | lower }}",
327
+ "output": "{{ tool_result }}",
328
+ "output_name": "error_route",
329
+ "output_type": str
330
+ },
331
+ {
332
+ "condition": "{{ 'error' not in tool_result.text | lower }}",
333
+ "output": "{{ tool_result }}",
334
+ "output_name": "success_route",
335
+ "output_type": str
336
+ }
337
+ ]
338
+ router = ConditionalRouter(routes)</code></pre>
339
  </div>
340
+ </section>
341
 
342
+ <!-- KAPITEL 8: REPOSITORY UND CODE -->
343
+ <section id="repo">
344
+ <h2 class="bg-hfYellow/20 -mx-6 px-6 py-4 rounded-xl text-yellow-900 border-l-4 border-hfYellow">
345
+ <span>📁</span> 8. Repository-Struktur: Der Master-Plan
346
+ </h2>
347
+ <p>Alle Code-Schnipsel aus Kapitel 3 bis 7 fügen sich nun zusammen. Ein komplexes MAS sollte <strong>niemals ein Monolith</strong> sein (alles in einem Skript). Eine monolithische Architektur würde das Testen einzelner Pipelines fast unmöglich machen und zu Spaghetti-Code beim Routing führen.</p>
348
+
349
+ <p>Dank der modularen Architektur von Haystack 2.0 spiegelt sich die fachliche Trennung direkt im Repository wider:</p>
350
+
351
+ <div class="bg-gray-50 border border-gray-200 rounded-lg p-5 mb-8 font-mono text-sm text-gray-700 leading-relaxed shadow-sm">
352
+ infinite-cookbook/<br>
353
+ ├── <span class="font-bold text-gray-900">schemas/</span><br>
354
+ │ └── <span class="text-blue-600">recipe.py</span> <span class="text-gray-400 italic"># (Kapitel 4) Pydantic Modelle</span><br>
355
+ ├── <span class="font-bold text-gray-900">components/</span><br>
356
+ │ └── <span class="text-blue-600">image_generator.py</span> <span class="text-gray-400 italic"># (Kapitel 5) Custom @component</span><br>
357
+ ├── <span class="font-bold text-gray-900">templates/</span><br>
358
+ │ └── <span class="text-blue-600">recipe_card.html</span> <span class="text-gray-400 italic"># (Kapitel 6) Jinja2 Template</span><br>
359
+ ├── <span class="font-bold text-gray-900">agents/</span><br>
360
+ │ ├── <span class="text-blue-600">researcher.py</span> <span class="text-gray-400 italic"># (Kapitel 3) Web-Search Pipeline</span><br>
361
+ │ └── <span class="text-gray-500">structurer.py ...</span><br>
362
+ ├── <span class="font-bold text-gray-900">tools/</span><br>
363
+ │ └── <span class="text-blue-600">agent_tools.py</span> <span class="text-gray-400 italic"># (Kapitel 7) Pipeline -> Tool Wrapper</span><br>
364
+ └── <span class="text-blue-600 font-bold">main.py</span> <span class="text-gray-400 italic"># Orchestrierungs-Loop (siehe unten)</span>
365
+ </div>
366
+
367
+ <h3>Das Herzstück: <code>main.py</code></h3>
368
+ <p>Weil wir alle Komplexität in die Unterordner ausgelagert haben, ist die <code>main.py</code> unglaublich elegant. Sie initialisiert das Haupt-LLM, importiert die fertige Werkzeugkiste und startet die Interaktions-Schleife.</p>
369
+
370
  <div class="code-wrapper mt-4">
371
  <div class="file-label">main.py</div>
372
  <button class="copy-btn" onclick="copyCode(this)">Copy</button>
 
376
  from haystack.components.tools import ToolInvoker
377
  from haystack.dataclasses import ChatMessage
378
 
379
+ # Der saubere Import aus unserer Architektur (Kapitel 7)
380
  from tools.agent_tools import cookbook_tools
381
 
382
  def main():
383
+ # 1. Der Koordinator: Ein starkes Modell (z.B. Qwen), das Tool-Calling beherrscht
384
  llm = HuggingFaceAPIChatGenerator(
385
  api_type="serverless_inference_api",
386
  model="Qwen/Qwen2.5-72B-Instruct",
 
390
  # 2. Der Invoker: Führt die vom LLM gewählten Tools aus
391
  invoker = ToolInvoker(tools=cookbook_tools)
392
 
393
+ # 3. Der Orchestrierungs-Graph aufbauen
394
  coordinator = Pipeline()
395
  coordinator.add_component("llm", llm)
396
  coordinator.add_component("invoker", invoker)
397
 
398
+ # Zyklische Verbindung für iteratives Arbeiten (Das LLM evaluiert Tool-Outputs)
399
  coordinator.connect("llm.replies", "invoker.messages")
400
  coordinator.connect("invoker.tool_messages", "llm.messages")
401
 
 
405
 
406
  print(f"🤖 Koordinator startet Aufgabe: {user_prompt}")
407
 
408
+ # Run Loop
409
+ # Im echten MAS läuft dies in Verbindung mit dem Router in einer Schleife,
410
+ # bis das LLM entscheidet: "Ich bin fertig, hier ist das finale HTML."
411
  result = coordinator.run({"llm": {"messages": messages}})
412
 
 
 
413
  print("Fertiges Ergebnis:", result["llm"]["replies"][0].text)
414
 
415
  if __name__ == "__main__":
 
420
  <span class="text-2xl">💡</span>
421
  <div>
422
  <strong class="text-gray-900 block mb-1">Die Architektur-Philosophie:</strong>
423
+ Diese Aufteilung erlaubt es dir, das Modell in <code>main.py</code> auszutauschen, die Such-Logik in <code>researcher.py</code> komplett neu zu schreiben oder an der HTML-Karte zu basteln, ohne dass die anderen Teile des Multi-Agenten-Systems zerbrechen. Das ist die Stärke von Haystack 2.0!
424
  </div>
425
  </div>
426
 
 
446
  sidebar.classList.toggle('hidden');
447
  });
448
 
449
+ // Smooth scroll adjustment for fixed header
450
  document.querySelectorAll('a[href^="#"]').forEach(anchor => {
451
  anchor.addEventListener('click', function (e) {
452
  e.preventDefault();
 
459
  a.classList.remove('bg-hfYellow/20', 'text-yellow-800', 'font-semibold');
460
  a.classList.add('text-gray-600');
461
  });
462
+
463
+ if(this.getAttribute('href') !== '#repo') {
464
+ this.classList.remove('text-gray-600');
465
+ this.classList.add('bg-hfYellow/20', 'text-yellow-800', 'font-semibold');
466
+ }
467
 
468
  document.querySelector(this.getAttribute('href')).scrollIntoView({
469
  behavior: 'smooth'