import streamlit as st import openai import re from duckduckgo_search import DDGS # --- Araçların Tanımlanması --- def search_tool(query: str): """A web search tool that uses DuckDuckGo to find information.""" st.write(f"🔎 Web'de aranıyor: `{query}`") try: with DDGS() as ddgs: results = [r for r in ddgs.text(query, max_results=5)] return "\n".join(results) if results else "Aramada sonuç bulunamadı." except Exception as e: return f"Arama sırasında bir hata oluştu: {e}" def calculator_tool(expression: str): """A calculator tool that evaluates a mathematical expression.""" st.write(f"🧮 Hesaplama yapılıyor: `{expression}`") try: # Güvenlik için sadece güvenli karakterlere izin ver if not re.match(r"^[0-9+\-*/.() \t]+$", expression): return "Geçersiz karakterler içerdiği için hesaplama yapılamadı." result = eval(expression) return f"Sonuç: {result}" except Exception as e: return f"Hesaplama hatası: {e}" # --- LLM (Büyük Dil Modeli) İstek Fonksiyonu --- def call_llm(prompt, api_key): """Calls the OpenAI API to get the agent's next thought and action.""" openai.api_key = api_key try: response = openai.chat.completions.create( model="gpt-4o", # veya "gpt-3.5-turbo" messages=[{"role": "user", "content": prompt}], temperature=0.0, max_tokens=500, ) return response.choices[0].message.content except Exception as e: st.error(f"OpenAI API çağrısı sırasında hata: {e}") return None # --- Ana Ajan Döngüsü --- def run_agent_loop(goal, api_key): """Runs the main ReAct (Reason-Act) agent loop.""" # Ajanın nasıl çalışacağını açıklayan ana prompt (talimat) system_prompt_template = f""" Sen, bir amaca ulaşmak için adım adım düşünen ve araçları kullanan bir AI ajanısın. Her adımda, amacına yönelik bir 'Düşünce' ve bu düşünceyi hayata geçirecek bir 'Eylem' üretmelisin. Kullanabileceğin araçlar şunlardır: 1. `search(sorgu)`: İnternette arama yapmak için kullanılır. Örneğin: `search(Türkiye'nin başkenti)` 2. `calculator(ifade)`: Matematiksel bir ifadeyi hesaplamak için kullanılır. Örneğin: `calculator(100 * (3 + 5))` 3. `finish(cevap)`: Görevi tamamladığında ve nihai cevabı bulduğunda kullanılır. Örneğin: `finish(Ankara, Türkiye'nin başkentidir.)` Süreç şu şekilde işler: 1. Amacı analiz edersin. 2. Bir 'Düşünce' oluşturursun. 3. Bir 'Eylem' seçersin. 4. Ben sana 'Gözlem' olarak eylemin sonucunu veririm. 5. Amaca ulaşana kadar 2-4 adımlarını tekrarlarsın. Amacımız: "{goal}" Şimdi, ilk Düşünce ve Eylemini yaz. """ history = [system_prompt_template] max_steps = 10 for step in range(max_steps): st.write("---") st.info(f"🚀 Adım {step + 1}") prompt = "\n".join(history) with st.spinner("Ajan düşünüyor..."): response = call_llm(prompt, api_key) if not response: st.error("Ajan bir yanıt üretemedi. Lütfen API anahtarınızı kontrol edin veya tekrar deneyin.") break # LLM'in ürettiği Düşünce ve Eylemi ayıkla try: thought = re.search(r"Düşünce: (.*?)\n", response, re.DOTALL).group(1).strip() action_full = re.search(r"Eylem: (.*?)$", response, re.DOTALL).group(1).strip() except AttributeError as e: st.error("Ajan geçerli bir 'Düşünce' veya 'Eylem' formatı üretmedi.") st.write(response) # Hata mesajı ve yanıtı tam olarak görmek için break with st.expander("🤖 Ajanın Düşünce Süreci", expanded=True): st.markdown(f"**Düşünce:** {thought}") st.markdown(f"**Eylem:** `{action_full}`") # Eylemi formatına göre ayıklama action_name_match = re.match(r"(\w+)\((.*)\)", action_full) if not action_name_match: st.error(f"Geçersiz eylem formatı: {action_full}") break action_name = action_name_match.group(1) action_input = action_name_match.group(2).strip(' "') # Eylemi gerçekleştir ve gözlemi al observation = "" if action_name == "search": observation = search_tool(action_input) elif action_name == "calculator": observation = calculator_tool(action_input) elif action_name == "finish": st.success(f"✅ Ajan görevi tamamladı!") st.balloons() st.markdown("### Nihai Cevap:") st.write(action_input) break else: observation = f"Bilinmeyen eylem: {action_name}. Lütfen `search`, `calculator` veya `finish` kullanın." st.warning(f"**Gözlem:**\n{observation}") # Geçmişi güncelle history.append(response) history.append(f"Gözlem: {observation}") else: st.error("Ajan maksimum adım sayısına ulaştı ama görevi tamamlayamadı.") # --- Streamlit Arayüzü --- st.set_page_config(page_title="AI Agentic App", page_icon="🤖") st.title("🤖 AI Agent Uygulaması") st.markdown(""" Bu uygulama, bir amaca ulaşmak için **ReAct (Reason + Act)** mantığıyla çalışan bir AI ajanıdır. Ajan, hedefe ulaşmak için **düşünür**, **araçlar kullanır** (web araması, hesap makinesi) ve sonuçları **gözlemler**. """) st.sidebar.header("API Yapılandırma") api_key = st.sidebar.text_input("OpenAI API Anahtarınız", type="password", help="API anahtarınız asla saklanmaz.") st.header("Ajanın Amacını Belirleyin") goal = st.text_input( "Amaç:", placeholder="Örnek: 'Matrix filminin başrol oyuncusunun bugünkü yaşı kaçtır ve bu yaşın karekökü nedir?'" ) if st.button("Ajanı Başlat", disabled=(not api_key or not goal)): if api_key and goal: run_agent_loop(goal, api_key) else: st.warning("Lütfen OpenAI API anahtarınızı ve bir amaç girin.")