iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
AI & Data

RAG × Agent:從知識檢索到智慧應用的30天挑戰系列 第 27

Day 27|實戰 AutoGen:讓模型自己選工具(Tool Selection 篇)

  • 分享至 

  • xImage
  •  

昨天我們讓系統具備了「會查條文、會記得你說過什麼」的能力,但這些功能仍然是人工判斷。
今天要邁向真正的「Agent」:讓模型自己看到工具列表後,決定何時使用哪個工具。

今天的目標有:

  • 讓模型知道有哪些可用工具(例如:查法條、RAG 檢索)
  • 讓模型自己選要不要使用工具來回答問題。
  • 讓我們能看出模型選用了哪個工具(方便日誌與分析)。

檔案架構

一樣只有新增新的檔案,不要刪掉舊的資料夾窩><

project/
└─ agent/
   └─ agent_autogen.py      # AutoGen Tool Selection MVP

前置處理(安裝 AutoGen)

pip install pyautogen
pip install "autogen-ext[ollama]"

雖然之前都有說到要用 AutoGen 但好像都還沒有好好介紹他,他其實是是微軟開源的「多 Agent 框架」,可以讓 LLM 在工具之間「互動、呼叫、溝通」。
但我們還不會用到 多 Agent 就是了~


1. 新增 agent/agent_autogen.py

先從最小可執行版本開始:我們只註冊兩個工具,讓模型自己選用。

import sys, json, argparse, asyncio
from pathlib import Path
from datetime import datetime

# 讓我們能 import 到 project/ 下的模組
sys.path.append(str(Path(__file__).resolve().parents[1]))

# 原本就有的工具函式
from rag.connect import search_chunks, build_prompt, ask_ollama, article_lookup
from utils.memory import memory_lines, remember

from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.ollama import OllamaChatCompletionClient

# --- 定義工具(直接用 Python 函式,Agent 會自動包 FunctionTool) ---
def lookup_article_tool(q: str) -> str:
    """直查第N條全文;適合『第X條是什麼?』"""
    return article_lookup(q) or "(沒有查到對應條文)"

def search_law_tool(query: str, k: int = 4) -> str:
    """一般問答:RAG 檢索 + 生成"""
    hits = search_chunks(query, k)
    prompt = build_prompt(query, hits, mem_lines=memory_lines())
    return ask_ollama(prompt).strip()

async def main():
    ap = argparse.ArgumentParser(description="AgentChat 單代理(工具選擇 MVP)")
    ap.add_argument("--q", required=True, help="問題內容")
    ap.add_argument("--model", default="mistral", help="Ollama 模型名(預設 mistral,例如 llama3)")
    ap.add_argument("--max_tool_iter", type=int, default=3, help="單次最多工具呼叫次數")
    ap.add_argument("--json_out", action="store_true", help="是否輸出 JSONL 到 logs/")
    args = ap.parse_args()

    # 建立 Ollama 模型客戶端
    model_client = OllamaChatCompletionClient(model=args.model)  # 預設 http://localhost:11434

    # 建立 agent,工具直接丟函式
    agent = AssistantAgent(
        name="law_agent",
        model_client=model_client,
        tools=[lookup_article_tool, search_law_tool],  # 讓模型自己決定用哪個
        system_message=(
            "你是台灣資安法規助理。遇到『第X條』請優先呼叫條文直接查詢;"
            "其他一般法規問題請用 RAG 檢索工具。回答務必簡潔、列點。"
        ),
        max_tool_iterations=args.max_tool_iter,
        reflect_on_tool_use=True,      # 讓模型對工具結果做一次短反思
        model_client_stream=False,     # 需要串流可改 True
    )

    # 跑起來
    result = await agent.run(task=args.q)
    answer = getattr(result, "content", str(result))

    print("\n=== 最終回答 ===")
    print(answer)

    # 記憶:寫入本次 Q/A 摘要
    remember(args.q, answer)

    # 統一 JSONL 日誌
    if args.json_out:
        logs = Path("logs"); logs.mkdir(parents=True, exist_ok=True)
        out = logs / f"run_{datetime.now():%Y%m%d}.jsonl"
        record = {
            "ts": datetime.now().isoformat(timespec="seconds"),
            "mode": "autogen-1agent",
            "query": args.q,
            "model": args.model,
            "answer": answer,
        }
        out.open("a", encoding="utf-8").write(json.dumps(record, ensure_ascii=False) + "\n")
        print(f"\n[log] 已寫入:{out}")

if __name__ == "__main__":
    asyncio.run(main())

之後可以嘗試輸入指令做測試:

python agent/agent_autogen.py --q "第14條是什麼?" --json_out

他可能輸出的東西你會看著很奇怪,但這是 AutoGen 預設的內容,方便我們除錯用,如果你還是看著不習慣,你可以自己處理,讓輸出更乾淨點~


明天會加上原先的 RAGAS,就不廢話了,明天見!


上一篇
Day 26|實戰工具化與記憶:讓系統會查條文、會記得你說過什麼
下一篇
Day 28|實戰 RAGAS:教 Agent 檢查自己答得好不好
系列文
RAG × Agent:從知識檢索到智慧應用的30天挑戰28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言