"""
🧠 Agent 8 模式练习 —— 在 VS Code 里打开这个文件，逐个模式练习
用法：选中一个模式的代码块 → Shift+Enter 运行 → 看输出改代码
"""

# ═══════════════════════════════════════════════════════════
# 模式 1：字典（dict）
# Agent 里无处不在 —— LLM 消息、工具参数、context 全是字典
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
message = {"role": "user", "content": "OpenAI 新闻"}

# 读
print(message["role"])       # 输出什么？

# 改
message["content"] = "15乘以37"
print(message)               # 输出什么？

# 加
message["name"] = "康锅"
print(message)               # 输出什么？

# 练完这题：自己建一个 tool_call 字典，包含 name 和 args（args 又是一个字典）
# 然后打印 args 里的 query 字段


# ═══════════════════════════════════════════════════════════
# 模式 2：函数（def）
# Agent 每个工具都是函数，run() 也是函数
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
def add_tool(name, description):
    """造一个工具描述"""
    return {"name": name, "description": description, "type": "function"}

tool = add_tool("calculate", "执行数学计算")
print(tool)                  # 输出什么？
print(tool["name"])          # 输出什么？

# 练完这题：写一个 build_messages(user_query) 函数
# 传入用户问题，返回 [{"role":"system","content":"你是助手"}, {"role":"user","content": user_query}]


# ═══════════════════════════════════════════════════════════
# 模式 3：列表（list）
# TOOLS 是列表，messages 是列表，搜索结果也是列表
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
messages = [
    {"role": "system", "content": "你是助手"},
    {"role": "user", "content": "你好"},
]

# 追加
messages.append({"role": "assistant", "content": "你好！有什么可以帮你？"})

# 访问
print(messages[0])           # 第一条消息
print(messages[1]["content"]) # 用户说了什么？
print(len(messages))          # 现在有多少条？

# 练完这题：建一个空列表 results = []，往里加 3 条搜索结果（字典），然后打印长度


# ═══════════════════════════════════════════════════════════
# 模式 4：for 循环
# Agent 遍历 tool_calls、搜索结果、测试用例
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
tool_calls = [
    {"name": "web_search", "args": {"query": "OpenAI"}},
    {"name": "calculate", "args": {"expression": "100*2"}},
]

for tc in tool_calls:
    print(f"调 {tc['name']}，参数 {tc['args']}")

# 练完这题：TOOLS = [{"name":"搜索","id":1},{"name":"计算","id":2},{"name":"查库","id":3}]
# 用 for 逐个打印 "工具X的id是Y"


# ═══════════════════════════════════════════════════════════
# 模式 5：if / else
# Agent 靠 if 判断要不要调工具、走哪个分支
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
def decide(query):
    if "搜索" in query:
        return "调用搜索工具"
    elif "计算" in query or "乘以" in query:
        return "调用计算工具"
    else:
        return "直接回答"

print(decide("搜索一下OpenAI"))  # 走哪个分支？
print(decide("15乘以37"))       # 走哪个分支？
print(decide("你好"))           # 走哪个分支？

# 练完这题：写一个 needs_tool(user_message)，如果消息里有"新闻"或"最新"返回 True，否则 False


# ═══════════════════════════════════════════════════════════
# 模式 6：f-string
# Agent 拼 prompt、打日志全靠它
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
step = 1
name = "搜索"
result = "3条结果"

print(f"第{step}步[{name}]：{result}")

tool_name = "web_search"
tool_args = {"query": "OpenAI"}
print(f"🔧 调用 {tool_name}，参数：{tool_args}")

# 练完这题：variables = {"user": "康锅", "model": "DeepSeek", "tokens": 1234}
# 用 f-string 输出 "康锅本次用了DeepSeek，消耗1234 tokens"


# ═══════════════════════════════════════════════════════════
# 模式 7：import
# openai、json、os——Agent 离不开库
# ═══════════════════════════════════════════════════════════

# --- 你的练习 ---
import json
import os

# json.loads：字符串 → 字典
raw = '{"query": "OpenAI 新闻"}'
parsed = json.loads(raw)
print(parsed["query"])           # 拿到 "OpenAI 新闻"

# json.dumps：字典 → 字符串
data = {"role": "tool", "content": "找到3条"}
text = json.dumps(data, ensure_ascii=False)
print(text)                      # 变成 JSON 字符串

# os.getenv：读环境变量
# print(os.getenv("HOME"))       # 你电脑的用户目录

# 练完这题：(1) 把 {"role":"tool","content":"ok"} 用 dumps 转成字符串
#          (2) 再把字符串用 loads 转回字典，打印 role


# ═══════════════════════════════════════════════════════════
# 模式 8：json（序列化）—— LLM 和代码的翻译官
# ═══════════════════════════════════════════════════════════

# --- 你的练习（跟模式 7 联动）---
# 模拟 Agent 里真实发生的事：

# LLM 返回的 tool_calls.arguments 是 JSON 字符串
llm_output = '{"query": "OpenAI", "max_results": 5}'
args = json.loads(llm_output)         # 代码解析
print(args["query"])                  # 拿到参数

# 工具执行完，结果要序列化回传给 LLM
search_result = [
    {"title": "OpenAI融资", "url": "https://...", "content": "100亿"},
    {"title": "GPT-5发布", "url": "https://...", "content": "超越前代"},
]
# 序列化（保留中文）
content_for_llm = json.dumps(search_result, ensure_ascii=False, indent=2)
print(content_for_llm)

# 练完这题：把字典 {"name":"康锅","score":100} 转成字符串再转回来，打印 score


# ═══════════════════════════════════════════════════════════
# 🏆 终极综合练习
# 把上面 8 个模式串起来，模拟 Agent 的核心流程
# ═══════════════════════════════════════════════════════════

def mini_agent(user_message: str) -> str:
    """微型 Agent：判断要不要搜索 → 执行 → 返回"""
    # 用字典存结果（模式 1）
    context = {}

    # 用 if 判断（模式 5）
    if "新闻" in user_message or "搜索" in user_message:
        # 用 f-string 打日志（模式 6）
        tool_name = "web_search"
        query = user_message.replace("搜索", "").replace("新闻", "").strip()
        print(f"🔧 调用 {tool_name}，关键词：{query}")

        # 模拟搜索（真实 Agent 这里调 API）
        results = [
            {"title": f"关于 {query} 的结果1", "url": "https://example.com/1"},
            {"title": f"关于 {query} 的结果2", "url": "https://example.com/2"},
        ]

        # 存进 context（模式 3 列表 + 模式 1 字典）
        context["search_results"] = results

        # 用 json 序列化（模式 8 / 模式 7）
        context["search_json"] = json.dumps(results, ensure_ascii=False)

    # 用 for 遍历结果（模式 4）
    if "search_results" in context:
        titles = []
        for r in context["search_results"]:           # 模式 4
            titles.append(r["title"])                  # 模式 3
        return f"找到{len(context['search_results'])}条：{'; '.join(titles)}"   # 模式 6

    return "不需要搜索，直接回答。"

# 测试
print("\n" + "="*50)
print(mini_agent("OpenAI 最新新闻"))
print(mini_agent("你好"))


# ═══════════════════════════════════════════════════════════
# 🎯 检验标准
# 关掉这个文件 → 新建一个空白 .py → 每个模式的练习不看答案敲出来
# 8 个全过 → 进 Phase 2
# ═══════════════════════════════════════════════════════════
