File size: 6,223 Bytes
0872fe3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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 Agent 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("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.")