Program
Tek bir modelden bir konuyu araştırmasını, bir makale taslağı yazmasını, gözden geçirmesini ve tek seferde son halini parlatmasını isterseniz, genelde dördünde de vasat bir sonuç alırsınız. Modelin herhangi bir anda net bir rolü olmaz; tüm işleri aynı anda yürütmeye çalışır ve bunların hiçbirini pek iyi yapamaz. Bu işi uzmanlaşmış ajanlara bölmek ise genelde daha güçlü bir sonuç üretir; çünkü her ajan kendi payına düşeni düzgün yapmaya odaklanabilir.
Bu rehberde tam olarak bunu yapan bir aracı sürüsü oluşturacağız. Ajanları koordine etmek için CrewAI'yi, akıl yürütme ve yazma gücü için Gemini 3.5 Flash'ı kullanacağız. Sürüde dört üye var: Güncel bilgileri toplayan bir Araştırmacı, ilk taslağı üreten bir Yazar, açıklık ve doğruluğu geliştiren bir Editör ve iş akışını koordine eden bir Yönetici.
Ayrıca Araştırmacıya Olostep aracılığıyla canlı web erişimi vereceğiz; böylece yalnızca modelin iç bilgisini değil, taze kaynakları da çekebilecek. Sonunda, bir konuyu alıp yayına hazır bir makale döndüren çalışan bir hiyerarşik sürünüz olacak — ve bu yaklaşımın ne zaman maliyete değdiğini, ne zaman değmediğini net biçimde göreceksiniz.
Aracı Sürüsü Nedir?
Aracı sürüsü, bir görevi tamamlamak için birlikte çalışan yapay zekâ ajanlarının bir grubudur. Bir modelden araştırma, yazma, inceleme ve sonlandırmayı tek başına yapmasını istemek yerine, aracı sürüsü işi birden çok uzmanlaşmış ajana böler. Her ajanın net bir rolü vardır ve sistem onları koordine ederek daha güçlü bir nihai sonuç üretir.
Avantajı uzmanlaşmadır. Araştırmaya odaklı bir ajan kaynak bulma ve doğrulamaya yoğunlaşabilir; yazmaya odaklı bir ajan yapı ve açıklığa odaklanabilir; bir editör ise az önce yazdığı metinden etkilenmeden taslağı özgün araştırmaya göre kontrol edebilir.
Koordine eden bir ajan adımları birbirine bağlar ve sırada ne olacağına karar verir. Burada kurduğumuz sürüde bu roller doğrudan Araştırmacı, Yazar, Editör ve Yöneticiye karşılık geliyor.

Elbette bunun bir bedeli var. Daha fazla ajan, daha fazla model çağrısı, daha fazla süre ve iş akışının hata verebileceği daha fazla nokta demektir; çalıştırmanın gerçek maliyetini gördükten sonra bu takasa yazının sonunda döneceğiz.
CrewAI Nedir?
CrewAI, çok ajanlı sistemler kurmak için açık kaynaklı bir çerçevedir. Ajanları tanımlamak, onlara görev atamak ve nasıl koordine olacaklarını seçmek için temiz bir yol sunar; böylece onları bağlayan tesisatla uğraşmak yerine rollere ve iş akışına odaklanabilirsiniz.
Üç kavram işi büyük ölçüde üstlenir.
- Ajanlar tek tek çalışanlardır; her biri davranışını şekillendiren bir rol, bir hedef ve bir geçmiş hikâyeyle tanımlanır.
- Görevler yapılacak işi ve her birinin üretmesi gereken çıktıyı açıklar.
- Bir ekip ajanları ve görevleri bir araya getirir ve seçilen bir süreç altında çalıştırır
Bu süreç sıralı olabilir; görevler sabit bir düzende çalışır. Ya da hiyerarşik olabilir; bir yönetici ajan işleri başkalarına delege eder ve çıktıyı doğrular. Burada hiyerarşik süreci kullanacağız; delege etmeyi Yönetici üstlenecek.
CrewAI ayrıca LiteLLM üzerinden model erişimini yönetir; bu, pek çok sağlayıcı için tek birleştirilmiş arayüz sunan açık kaynaklı bir kütüphanedir. Bu sayede tek bir Gemini 3.5 Flash modelini tanımlayıp dört ajanın tamamında yeniden kullanabiliyoruz; aşağıdaki adımlarda bunu kuracağız.
CrewAI ve Gemini 3.5 Flash ile Bir Aracı Sürüsü Kurma
Kurulumla başlayalım.
1. Önkoşullar
Başlamadan önce şunlara sahip olduğunuzdan emin olun:
- Python 3.11 veya daha yenisi kurulu
- Jupyter Notebook veya JupyterLab kurulu
- Python ve notebooklara dair temel bilgi
- Bir Google AI Studio hesabı
- Gemini kullanımı için Google hesabınızda faturalandırma etkin veya kredi eklenmiş
- Bir Olostep ücretsiz hesabı
2. Bağımlılıkları yükleyin
Jupyter Notebook veya JupyterLab'i başlatın ve ortamınızda mevcut en güncel Python çekirdeğiyle bir notebook açın. Ardından gerekli paketleri kurmak için aşağıdaki hücreyi çalıştırın.
%pip install --quiet -U \
crewai \
crewai-tools \
google-genai \
litellm \
olostep \
nest-asyncio
Kurulum tamamlandıktan sonra, yüklenen paket sürümlerini kontrol etmek için sonraki hücreyi çalıştırın. Bu, her şeyin doğru kurulduğunu teyit etmeye yardımcı olur.
import importlib.metadata as md
for pkg in [
"crewai",
"crewai-tools",
"google-genai",
"litellm",
"olostep",
"nest-asyncio",
]:
print(f"{pkg:>16} {md.version(pkg)}")
Şuna benzer bir çıktı görmelisiniz:
crewai 1.14.6
crewai-tools 1.14.6
google-genai 2.8.0
litellm 1.87.1
olostep 1.1.0
nest-asyncio 1.6.0
3. Ortam değişkenlerini ayarlayın
Bu proje için iki API anahtarına ihtiyacınız olacak.
Önce, Google AI Studio'dan bir Gemini API anahtarı oluşturun. Google AI Studio'yu açın, API key bölümüne gidin ve projeniz için yeni bir anahtar oluşturun. Gemini ücretsiz bir katman sunar, ancak kullanım ve hız sınırlamaları vardır. Gemini'yi daha güvenilir şekilde test etmek ve çalıştırmak için Google faturalandırma hesabınızı bağlayın veya ücretsiz katman sınırlarını aştığınızda kullanımın faturalandırılabilmesi için hesabınıza kredi ekleyin.
Sonra bir Olostep API anahtarı oluşturun. Olostep'e kaydolun, Olostep panosunu açın ve API keys sayfasından bir API anahtarı üretin. Bu anahtarı, Araştırmacı ajana arama ve sayfa kazıma için canlı web erişimi vermek üzere kullanacağız.
Her iki anahtar da hazır olduğunda, bunları ortam değişkeni olarak kaydedin. CrewAI ajanlarına güç veren Gemini olacak; Olostep ise Araştırmacı ajanın webden güncel bilgi toplamasını sağlayacak.
Her iki anahtarı da oluşturduktan sonra, notebooku çalıştırmadan önce ortam değişkeni olarak kaydedin.
PowerShell:
$env:GEMINI_API_KEY="your-gemini-key"
$env:OLOSTEP_API_KEY="your-olostep-key"
macOS/Linux:
export GEMINI_API_KEY="your-gemini-key"
export OLOSTEP_API_KEY="your-olostep-key"
Şimdi Gemini API anahtarının doğru yüklendiğini kontrol etmek için aşağıdaki hücreyi çalıştırın.
import os
api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
if not api_key:
raise RuntimeError(
"Set GEMINI_API_KEY or GOOGLE_API_KEY in your environment, "
"then restart the notebook kernel."
)
print(f"Gemini API key loaded")
Şunu görmelisiniz:
Gemini API key loaded
4. LiteLLM aracılığıyla Gemini 3.5 Flash'ı yapılandırın
Bu projede, tüm CrewAI ajanları için paylaşılan LLM olarak Gemini 3.5 Flash kullanacağız. Gemini 3.5 Flash; hızlı, ajan odaklı ve kodlamaya dönük iş yükleri için tasarlanmıştır. Ajanlarımızın çok adımlı akıl yürütmesi, talimatlara uyması, araçlarla çalışması ve yapılandırılmış çıktılar üretmesi gerektiği için bu proje için uygundur.
Gemini 3.5 Flash; geniş bağlam penceresi, uzun çıktılar, düşünme ve araç kullanımı desteği sunar; bu da onu ajan iş akışları için güçlü bir seçenek yapar. Bir aracı sürüsü, Araştırmacı, Yazar, Editör ve Yönetici ajanları boyunca modeli birkaç kez çağırabilir; Flash model kullanmak, güçlü akıl yürütme ve yazım kalitesini korurken iş akışının tepkisel kalmasına yardımcı olur.
Modeli diğer son teknoloji LLM'lerle karşılaştırmak isterseniz, Gemini 3.5 Flash vs GPT-5.5 ve Gemini 3.5 Flash vs Claude Opus 4.8 rehberlerimizi okumanızı öneririm.
Gemini'ye LiteLLM üzerinden erişeceğiz. LiteLLM, Gemini, OpenAI, Anthropic, Bedrock, Vertex AI ve diğer birçok sağlayıcıyı tek birleştirilmiş arayüzle çağırmanızı sağlayan açık kaynaklı bir kütüphanedir. Bu kurulumda, CrewAI arka planda LiteLLM kullanır; böylece Gemini model adını basit bir provider/model formatında iletebiliriz.
Şimdi paylaşılan bir CrewAI LLM'i oluşturup tüm ajanlarda yeniden kullanacağız. Bu, kurulumu basit tutar; çünkü Araştırmacı, Yazar, Editör ve Yönetici aynı Gemini modelini kullanacaktır.
from crewai import LLM
GEMINI_MODEL = "gemini/gemini-3.5-flash"
gemini_llm = LLM(
model=GEMINI_MODEL,
api_key=os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY"),
temperature=1.0,
)
print(f"LLM ready: {gemini_llm.model}")
print("Provider API: Google Gemini (via LiteLLM)")
Şuna benzer bir çıktı görmelisiniz:
LLM ready: gemini-3.5-flash
Provider API: Google Gemini (via LiteLLM)
Bu, CrewAI'nin artık LiteLLM üzerinden Gemini'ye erişebildiğini doğrular. Sonraki adımlarda bu paylaşılan gemini_llm nesnesini her ajana geçeceğiz.
5. Canlı web erişimi ekleyin
Araştırmacı ajanın güncel bilgilere erişmesi gerekir. Bunu yapmak için özel bir Olostep arama aracı oluşturup daha sonra Araştırmacı ajana vereceğiz.
Bu araç iki modda çalışabilir. Yalnızca arama özetlerini döndürebilir (daha hızlıdır) veya sonuç sayfalarını kazıyıp sayfa içeriğini markdown olarak döndürebilir. Ayrıca ajan web aracını çok fazla kez çağırmasın diye küçük bir arama bütçesi ekliyoruz.
from pydantic import Field, PrivateAttr
from crewai.tools import BaseTool
try:
from olostep import Olostep, Olostep_BaseError
except ImportError:
raise ImportError(
"The 'olostep' package is not installed. Run %pip install -U olostep."
)
Önce ortamdan Olostep API anahtarını yükleyin.
olostep_api_key = os.getenv("OLOSTEP_API_KEY")
if not olostep_api_key or olostep_api_key == "your-olostep-api-key-here":
print(
"The Olostep tool will fail at call time unless OLOSTEP_API_KEY "
"is set in the environment."
)
else:
print("Olostep API key loaded.")
_olostep_client = Olostep(api_key=olostep_api_key) if olostep_api_key else None
Şimdi özel CrewAI aracını oluşturun.
class OlostepSearchTool(BaseTool):
"""Search the web with a strict research-call budget."""
name: str = "olostep_web_search"
description: str = (
"Search the live web. Set scrape=false for fast discovery and "
"scrape=true for full-page evidence. You have at most 3 discovery "
"searches without scraping and 6 external search calls total. After "
"3 discovery searches, use scrape=true on the strongest query or "
"domain. Each call returns at most 3 results. Inputs: query, scrape, "
"limit, and optional include_domains."
)
default_limit: int = Field(default=3, ge=1, le=3)
max_chars_per_page: int = Field(default=4000, ge=500, le=12000)
_total_calls: int = PrivateAttr(default=0)
_discovery_calls: int = PrivateAttr(default=0)
_call_history: list[dict] = PrivateAttr(default_factory=list)
def _run(
self,
query: str,
scrape: bool = False,
limit: int | None = None,
include_domains: list[str] | None = None,
) -> str:
if _olostep_client is None:
return (
"OLOSTEP_API_KEY is not set. Set it in the environment "
"and restart the kernel."
)
if self._total_calls >= 6:
return (
"Research search budget exhausted: 6 external calls have "
"already been used. Stop searching and complete the task "
"with the collected sources."
)
if not scrape and self._discovery_calls >= 3:
return (
"Discovery-search limit reached. Do not run another "
"scrape=False search. Use scrape=True on the strongest query "
"or selected domains, or finish with the sources already found."
)
clean_query = query.strip()
if not clean_query:
return "Search query cannot be empty."
result_limit = max(1, min(limit or self.default_limit, 3))
kwargs = {"query": clean_query, "limit": result_limit}
if scrape:
kwargs["scrape_options"] = {
"formats": ["markdown"],
"timeout": 25,
}
if include_domains:
kwargs["include_domains"] = include_domains
self._total_calls += 1
if not scrape:
self._discovery_calls += 1
call_record = {
"number": self._total_calls,
"query": clean_query,
"scrape": scrape,
"limit": result_limit,
"domains": include_domains or [],
"status": "started",
"results": 0,
}
self._call_history.append(call_record)
try:
search = _olostep_client.searches.create(**kwargs)
except Olostep_BaseError as error:
call_record["status"] = "error"
call_record["error"] = f"{type(error).__name__}: {error}"
return (
f"Olostep search error: {type(error).__name__}: {error}\n"
f"Budget used: {self._total_calls}/6 total calls; "
f"{self._discovery_calls}/3 discovery calls."
)
if not search.links:
call_record["status"] = "no_results"
return (
f"No results found for query: {clean_query!r}\n"
f"Budget used: {self._total_calls}/6 total calls; "
f"{self._discovery_calls}/3 discovery calls."
)
call_record["status"] = "success"
call_record["results"] = len(search.links)
chunks = [
f"## Web results for: {clean_query!r}",
f"Page scraping: {'enabled' if scrape else 'disabled'}",
(
f"Budget used: {self._total_calls}/6 total calls; "
f"{self._discovery_calls}/3 discovery calls."
),
]
for index, link in enumerate(search.links, 1):
url = link.get("url", "")
title = link.get("title") or url or "Untitled result"
description = link.get("description") or "No description provided."
chunks.append(
f"### {index}. {title}\n"
f"URL: {url}\n"
f"Summary: {description}"
)
markdown = link.get("markdown_content")
if scrape and markdown:
body = markdown.strip()
if len(body) > self.max_chars_per_page:
body = body[: self.max_chars_per_page] + "\n...[truncated]"
chunks.append(f"Page content:\n{body}")
return "\n\n".join(chunks)
Son olarak aracın bir örneğini oluşturun.
olostep_search_tool = OlostepSearchTool()
print(f"Tool ready: {olostep_search_tool.name}")
Şuna benzer bir çıktı görmelisiniz:
Olostep API key loaded.
Tool ready: olostep_web_search
Bu, Olostep web arama aracının hazır olduğunu doğrular. İleride bu aracı Araştırmacı ajana ekleyeceğiz; böylece webden güncel bilgi toplayabilecek.
6. Ajanları oluşturun
Şimdi sürümüz için ajanları oluşturacağız. Üç çalışan ajan ve bir yönetici ajan tanımlayacağız. Çalışan ajanlar ana görevleri yapar; yönetici iş akışını koordine eder.
Araştırmacı ajan güncel bilgileri bulmak için Olostep aracını kullanacak. Yazar ajan araştırmayı bir taslağa dönüştürecek. Editör ajan taslağı iyileştirecek. Yönetici ajan ise hiyerarşik ekipte işin nasıl delege edileceğine karar verecek.
Çalışan ajanları oluşturun
Üç çalışan ajanla başlayalım.
from crewai import Agent
researcher = Agent(
role="Senior Research Analyst",
goal=(
"Find accurate, current, and well-sourced information about {topic}. "
"Produce concrete, verifiable points for the writer."
),
backstory=(
"You are a meticulous research analyst. You decide whether each web "
"search needs page scraping. Use scrape=False when titles, URLs, and "
"summaries are enough. Use scrape=True when you need full-page evidence "
"to verify a claim or understand a source in detail. Cite source URLs."
),
llm=gemini_llm,
tools=[olostep_search_tool],
verbose=True,
allow_delegation=False,
)
Şimdi Yazar ajanı oluşturun.
writer = Agent(
role="Blog Post Writer",
goal=(
"Turn the research into a complete, publication-ready educational "
"article on {topic}. Include a strong title, an unlabeled italic "
"summary, TL;DR, detailed body sections, conclusion, and FAQs. Add a "
"table only when it makes a comparison or decision easier to understand."
),
backstory=(
"You are a seasoned technology educator and writer. You create "
"practical, approachable articles similar in structure to high-quality "
"DataCamp content, without copying its wording or branding. You use "
"clear headings, short paragraphs, concrete examples, and sourced facts."
),
llm=gemini_llm,
verbose=True,
allow_delegation=False,
)
Şimdi Editör ajanını oluşturun.
reviewer = Agent(
role="Senior Editor",
goal=(
"Review the draft for factual accuracy, clarity, structure, and "
"completeness. Ensure it follows the required article order and return "
"a polished, publication-ready version."
),
backstory=(
"You are a detail-oriented senior editor for an educational technology "
"publication. You verify claims, improve flow, remove repetition, and "
"ensure the title is followed by an unlabeled italic summary and TL;DR. "
"You keep a table only when it adds real value, remove any Key Takeaways "
"section, and ensure Conclusion appears immediately before FAQs."
),
llm=gemini_llm,
verbose=True,
allow_delegation=False,
)
Yönetici ajanı oluşturun
Son olarak Yönetici ajanı oluşturun.
manager = Agent(
role="Content Coordinator",
goal=(
"Coordinate research, writing, and review for {topic}. Delegate each "
"task to the correct specialist and ensure the reviewed article is the "
"final result."
),
backstory=(
"You are an experienced editorial lead. You keep the workflow simple: "
"research first, writing second, and editorial review last."
),
llm=gemini_llm,
verbose=True,
allow_delegation=True,
)
Yönetici, hiyerarşik ekibi kurarken ayrı yapılandırılır. Bu yüzden henüz çalışan ajan listesine eklenmedi.
7. Görevleri tanımlayın
Şimdi aracı sürüsü için görevleri tanımlayacağız. Bu görevler doğrudan çalışan ajanlara atanmaz. Bunun yerine, hangi görevi kimin üstleneceğine Yönetici ajan karar verir.
Bu iş akışında ilk görev araştırma, ikincisi yazma, üçüncüsü incelemedir. Her görev, ajanların tam olarak ne üretmesi gerektiğini bilmeleri için beklenen bir çıktı da içerir.
from crewai import Task
research_task = Task(
description=(
"Delegate to the Senior Research Analyst. Research '{topic}' using at "
"most 6 web-tool calls. Use no more than 3 calls with scrape=False, "
"then use scrape=True only when detailed evidence is needed. Collect "
"5-7 useful findings, source URLs, and common reader questions."
),
expected_output=(
"Clear markdown research notes with 5-7 sourced findings and 3-5 "
"potential FAQ questions."
),
)
Sonraki adımda yazım görevini oluşturun. Bu görev, Yazarın toplanan araştırmadan makaleyi inşa edebilmesi için bağlam olarak araştırma görevini kullanır.
write_task = Task(
description=(
"Delegate to the Blog Post Writer. Write one complete educational "
"markdown article on '{topic}', approximately 1,000-1,500 words. Start "
"with one H1 title and an unlabeled italic summary. Then include TL;DR, "
"an introduction, useful body sections, an optional table only when it "
"improves understanding, a Conclusion, and FAQs. Use source links."
),
expected_output=(
"One continuous publication-ready markdown article with title, italic "
"summary, TL;DR, body, Conclusion, and 3-5 FAQs."
),
context=[research_task],
)
Şimdi inceleme görevini oluşturun. Bu görev, Editörün makaleyi özgün araştırmaya göre kontrol edebilmesi için bağlam olarak hem araştırma hem yazım görevlerini kullanır.
review_task = Task(
description=(
"Delegate to the Senior Editor. Review the article for accuracy, "
"clarity, structure, and source support. Return only the corrected full "
"article. Keep the same continuous article format and ensure FAQs are "
"the final section."
),
expected_output=(
"Only the final reviewed markdown article, beginning with its H1 title "
"and ending with the final FAQ answer."
),
context=[research_task, write_task],
)
Son olarak, üç görevi bir listeye ekleyin.
tasks = [research_task, write_task, review_task]
print(f"Defined {len(tasks)} manager-delegated tasks.")
Şunu görmelisiniz:
Defined 3 manager-delegated tasks.
8. İş akışını kurun
Şimdi ajanları ve görevleri tek bir CrewAI iş akışında bağlayacağız. Yönetici ajanın çalışan ajanları koordine ettiği hiyerarşik bir süreç kullanacağız.
Bu düzende Araştırmacı, Yazar ve Editör çalışan ajan olarak eklenir. Yönetici ise manager_agent parametresiyle ayrıca geçirilir; çünkü delege ve koordinasyondan sorumludur.
from crewai import Crew, Process
crew = Crew(
agents=[researcher, writer, reviewer],
tasks=tasks,
manager_agent=manager,
process=Process.hierarchical,
verbose=True,
memory=False,
)
Şimdi iş akışının doğru biçimde kurulduğunu doğrulamak için ekip ayrıntılarını yazdırın.
print("Hierarchical crew assembled.")
print(f" Workers : {[a.role for a in crew.agents]}")
print(f" Manager : {crew.manager_agent.role}")
print(f" Tasks : {len(crew.tasks)}")
print(f" Process : {crew.process}")
Şuna benzer bir çıktı görmelisiniz:
Hierarchical crew assembled.
Workers : ['Senior Research Analyst', 'Blog Post Writer', 'Senior Editor']
Manager : Content Coordinator
Tasks : 3
Process : Process.hierarchical
Bu, hiyerarşik aracı sürüsünün hazır olduğunu doğrular. Sonraki adımda ekibi bir konu üzerinde çalıştırıp nihai yanıtı üreteceğiz.
9. Aracı sürüsünü çalıştırın
Artık aracı sürüsünü çalıştırabiliriz. Bir konu sağlayıp iş akışını kickoff_async() ile başlatacağız.
Jupyter arka planda zaten bir olay döngüsü çalıştırır. Bu nedenle, eşzamanlı olmayan CrewAI iş akışının notebook içinde çalışabilmesi için önce nest_asyncio uygularız.
try:
import nest_asyncio
nest_asyncio.apply()
print("nest_asyncio applied: CrewAI can now run inside this kernel.")
except ModuleNotFoundError:
print("nest_asyncio not installed. Run: pip install nest-asyncio")
Şunu görmelisiniz:
nest_asyncio applied: CrewAI can now run inside this kernel.
Ardından bir konu tanımlayıp ekibi çalıştırmak için bir yardımcı işlev oluşturun.
from datetime import datetime
topic = "Learning Adaptive Thresholds for LLM Tool Use: When to Rely on Memory and When to Call a Tool"
async def run_crew(topic: str):
"""Run the CrewAI crew asynchronously."""
print(f"Starting crew at {datetime.now().isoformat(timespec='seconds')}")
print(f"Topic: {topic!r}\n")
result = await crew.kickoff_async(inputs={"topic": topic})
print(f"\nFinished at {datetime.now().isoformat(timespec='seconds')}")
print(f"Result type: {type(result).__name__}")
return result
result = await run_crew(topic)
İş akışı başladığında, CrewAI önce görevi Yönetici ajana verir. Yönetici, araştırma işini Kıdemli Araştırma Analistine delege eder. Araştırmacı, uyarlamalı eşikler, LLM araç kullanımı, bellek ve araç çağırma kararları hakkında bilgi bulmak için olostep_web_search aracını kullanır.

Günlükte, Araştırmacı hem yalnızca arama hem kazıma çağrılarını kullanır. Arama bütçesi tamamen kullanılır; toplam 6/6 web çağrısına ve 3/3 keşif çağrısına ulaşılır. Keşif arama sınırı aşıldığından ek bir yalnız arama isteği engellenir. Bu, özel Olostep aracımızdaki bütçe kurallarının doğru çalıştığını gösterir.

Araştırma aşamasından sonra Yönetici yazım ve inceleme adımlarını delege ederek iş akışını sürdürür. Ajanlar araştırma notları üretir, makale taslağını yazar ve ardından nihai yanıtı cilalar. Çalıştırma başarıyla tamamlanır ve bir CrewOutput nesnesi döner.
Şuna benzer bir çıktı görmelisiniz:
Starting crew at 2026-06-05T13:54:07
Topic: 'Learning Adaptive Thresholds for LLM Tool Use: When to Rely on Memory and When to Call a Tool'
Crew Execution Started
Task Started
Agent: Content Coordinator
Agent: Senior Research Analyst
Tool: olostep_web_search
Budget used: 6/6 total calls; 3/3 discovery calls
Finished at 2026-06-05T13:59:29
Result type: CrewOutput
Bu, tam sürünün başarıyla çalıştığı anlamına gelir. Yönetici iş akışını koordine etti; Araştırmacı güncel bilgileri topladı; Yazar taslağı oluşturdu ve Editör nihai çıktıyı iyileştirdi.
10. Sonucu görüntüleyin
Sürü çalışmasını bitirdikten sonra, ekibin oluşturduğu nihai makaleyi görüntüleyebiliriz. result.raw değeri iş akışının nihai yanıtını içerir.
from IPython.display import Markdown, display
raw = result.raw
if "Blog Post" in raw:
raw = raw.split("Blog Post", 1)[1].strip()
display(Markdown(raw))
Bu, nihai çıktıyı notebook içinde biçimlendirilmiş markdown olarak işleyecektir.
Çoğu durumda üretilen blog, birden çok başlık, net bölümler, uygun yerlerde diyagramlar veya görsel açıklamalar ve güçlü bir sonuç bölümüyle iyi yapılandırılmış olacaktır.
Araştırma, yazım ve editoryal incelemenin birleşimi, yayına hazır içerik üretmeye yardımcı olur. Çıktıyı inceledikten sonra, şahsen yayımlanması için onay verirdim.

Sırada bir yürütme izini yazdırabiliriz. Bu, sürünün nasıl çalıştığını, hangi ajanların katıldığını, kaç web çağrısı kullanıldığını ve her bir görevin nasıl işlendiğini anlamamıza yardımcı olur.
from collections import Counter
def role_name(value):
"""Return a readable role/name for CrewAI agent values."""
if value is None:
return "Not reported"
if isinstance(value, str):
return value
return getattr(value, "role", None) or getattr(value, "name", None) or str(value)
print("=" * 70)
print("SWARM EXECUTION TRACE")
print("=" * 70)
# Hierarchical crew structure
print("\nCOORDINATION")
print(f"Process : {crew.process}")
print(f"Manager : {role_name(crew.manager_agent)}")
print(f"Workers : {', '.join(role_name(agent) for agent in crew.agents)}")
print(
"Flow : Manager receives each task, delegates specialist work, "
"validates the response, and passes approved context to the next task."
)
Now print the web-tool usage recorded by the custom Olostep tool.
history = list(getattr(olostep_search_tool, "_call_history", []))
discovery_calls = sum(not item["scrape"] for item in history)
scrape_calls = sum(item["scrape"] for item in history)
successful_calls = sum(item["status"] == "success" for item in history)
print("\nWEB TOOL USAGE")
print(f"Total external calls : {len(history)}/6")
print(f"Without scraping : {discovery_calls}/3")
print(f"With scraping : {scrape_calls}")
print(f"Successful calls : {successful_calls}")
if history:
for item in history:
mode = "scrape" if item["scrape"] else "search only"
domains = ", ".join(item["domains"]) if item["domains"] else "all domains"
print(
f" {item['number']}. {mode}; status={item['status']}; "
f"results={item['results']}; scope={domains}"
)
print(f" Query: {item['query']}")
else:
print(" No Olostep calls were recorded.")
Finally, print the task-by-task trace.
print("\nTASK-BY-TASK TRACE")
agent_activity = Counter()
for index, task_out in enumerate(result.tasks_output, start=1):
task = crew.tasks[index - 1] if index <= len(crew.tasks) else None
reported_agent = role_name(getattr(task_out, "agent", None))
processed_by = sorted(getattr(task, "processed_by_agents", set()) or [])
participants = processed_by or [reported_agent]
for participant in participants:
agent_activity[role_name(participant)] += 1
delegations = getattr(task, "delegations", 0) if task else 0
used_tools = getattr(task, "used_tools", 0) if task else 0
tool_errors = getattr(task, "tools_errors", 0) if task else 0
start_time = getattr(task, "start_time", None) if task else None
end_time = getattr(task, "end_time", None) if task else None
duration = end_time - start_time if start_time and end_time else None
print(f"\n--- Task {index} ---")
print(f"Reported owner : {reported_agent}")
print(f"Processed by : {', '.join(map(role_name, participants))}")
print(f"Delegations : {delegations}")
print(f"Tool uses : {used_tools}")
print(f"Tool errors : {tool_errors}")
if duration is not None:
print(f"Duration : {duration}")
preview = getattr(task_out, "raw", "").strip().replace("\n", " ")
print(f"Output preview : {preview[:300]}{'...' if len(preview) > 300 else ''}")
print("\nAGENT ACTIVITY")
for agent, count in agent_activity.most_common():
print(f"{agent}: participated in {count} task(s)")
if not agent_activity:
print("CrewAI did not expose per-agent processing metadata for this run.")
Şuna benzer bir çıktı görmelisiniz:

Bu iz, hiyerarşik sürünün beklendiği gibi çalıştığını gösterir. Yönetici üç görevi de koordine etti; Araştırmacı araştırma adımını yürüttü; Yazar makale taslağını oluşturdu ve Editör nihai yanıtı iyileştirdi.
Ancak bu aynı zamanda önemli bir sınırlamayı da gösteriyor: çok ajanlı iş akışları pahalı hâle gelebilir.
Bu çalıştırmada iş akışı 6 harici web çağrısı ve Yönetici, Araştırmacı, Yazar, Editör boyunca birden çok LLM çağrısı kullandı. Tek bir çalıştırma yaklaşık 0,28 $ tutabilir; bu rehberi oluşturmak ise test sırasında yaklaşık 2,78 $'a mal oldu. Basit bir eğitim projesi için bu yüksek bir rakam.

Son Düşünceler
Aracı sürüleri ve çok ajanlı iş akışları kâğıt üzerinde harika görünür. Araştırmacı, Yazar, Editör ve Yöneticinin birlikte çalışması fikri güçlü hissettirir ve bu rehberde nihai çıktı gerçekten de küçük düzenlemelerle yayımlanacak kadar iyiydi.
Ama pratikte, bu kurulum daha pahalıya mal olabilir, daha uzun sürebilir ve daha fazla hata noktası yaratabilir. Benim durumumda bir çalıştırma yaklaşık 0,28 $; bu rehberi oluşturmak ise yaklaşık 2,78 $ tuttu. Basit bir eğitim projesi için bu oldukça fazla.
Gerçek uygulamalarda her zaman tam bir çok ajanlı sürü kullanmazdım. Basit görevlerin kod veya kurallarla yürütüldüğü, yalnızca karmaşık görevlerin ajanlara devredildiği daha programatik bir kurulumu tercih ederdim. Araç çağrılarını sınırlayarak, daha az ajan kullanarak, istemleri kısaltarak ve hiyerarşik yerine doğrusal bir iş akışı kullanarak maliyetleri de azaltabiliriz.
Elbette, çok fazla iyileştirdiğimizde artık gerçek bir aracı sürüsü olmayabilir. Daha çok kural tabanlı bir yapay zekâ iş akışına benzer. Bu yüzden hedef denge olmalı: gerçek değer kattıklarında aracı sürülerini kullanın; katmadıklarında işleri basit tutun.

Sertifikalı bir veri bilimcisi olarak, yenilikçi makine öğrenimi uygulamaları oluşturmak için en son teknolojileri kullanmaya büyük ilgi duyuyorum. Konuşma tanıma, veri analizi ve raporlama, MLOps, konuşma yapay zekası ve NLP alanlarında güçlü bir geçmişe sahip olarak, gerçek bir etki yaratabilecek akıllı sistemler geliştirme becerilerimi geliştirdim. Teknik uzmanlığımın yanı sıra, karmaşık kavramları açık ve özlü bir dille ifade etme yeteneğine sahip, becerikli bir iletişimciyim. Sonuç olarak, veri bilimi konusunda aranan bir blog yazarı oldum ve giderek büyüyen veri profesyonelleri topluluğuyla görüşlerimi ve deneyimlerimi paylaşıyorum. Şu anda, içerik oluşturma ve düzenlemeye odaklanıyorum. Büyük dil modelleriyle çalışarak, hem işletmelerin hem de bireylerin verilerinden en iyi şekilde yararlanmalarına yardımcı olabilecek güçlü ve ilgi çekici içerikler geliştiriyorum.