iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
生成式 AI

阿,又是一個RAG系列 第 9

Day8: Tavily 與 FunctionAgent

  • 分享至 

  • xImage
  •  

Situation:

  • 給定一個問題(question),我們正在尋求一個方法,可以幫我們找到對應的 context 以及 answer,來讓我們可以構造出 (context, question, answer) 這樣成對的 dataset
    • 其中 context 的角色是支持答案的外部依據

Task:

  • 我們今天來探索 llama_index 封裝的 Tavily research 工具

Action

  1. Setup
  • 首先我們需要去 tavily 申請 API key
    • 然後放到專案路徑下的 .env 檔案裡: TAVILY_API_KEY=xxxxxx
    • 免費版一個月有1000次的 Credits
  • 然後就是環境的設置
    • pip install llama-index-tools-tavily-research
  • import
    import os
    from dotenv import find_dotenv, load_dotenv
    _ = load_dotenv(find_dotenv())
    
    TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
    
  1. search 測試
  • search
    from llama_index.tools.tavily_research.base import TavilyToolSpec
    tavily_tool = TavilyToolSpec(
        api_key=TAVILY_API_KEY,
    )
    query = '徵象(Signs)及症狀(Symptoms)之區別?'
    tavily_response = tavily_tool.search(query, max_results=1)
    tavily_response
    
  • response
    • 回傳的是 list of llama_index 的 Document
    • metadata 包含了原文的 url
    • text 下放了主要的原文內容
    • 原始的 tavily api 應該還會回傳 title ,不過從 llama_index 的文件上來看沒有存 title.
    • https://ithelp.ithome.com.tw/upload/images/20250923/20177855k9U3rMK9xV.jpg
  1. 把 tavily search 做成 tool 給 agent 呼叫
  • 參考
    tavily_tool_list = tavily_tool.to_tool_list()
    print(tavily_tool_list[0].metadata.name)  # search
    from llama_index.core.agent.workflow import FunctionAgent
    from llama_index.llms.openai import OpenAI
    
    agent = FunctionAgent(
        tools=tavily_tool_list,
        llm=OpenAI(model="gpt-5-mini"),
        streaming=False,
        verbose=True,
    )
    
    result = await agent.run(query)
    print(result)
    
  • response
    • https://ithelp.ithome.com.tw/upload/images/20250923/2017785544zwscE0gg.jpg
    • 看起來是因為內建知識有,所以沒 call tool 就直接回答了
    • 因為 verbose 設 True 所以會看到類似 Running step init_run, Step init_run produced event AgentInput 這樣的 workflow 資訊,後續可以追蹤一下
  1. 硬塞個 prompt 要他 call tool 試試
  • prompt
    system_prompt = """
    你是一個考題助理,不能直接用自己的知識回答。
    
    任務流程:
    1. 根據使用者問題,先分析並決定最重要的 **關鍵字或子問題**(必須明確列出)。
    2. 對每個關鍵字或子問題,呼叫 tavily 搜尋工具來獲取相關資訊。
    3. 根據搜尋回傳的內容,整理出最終答案。
       - 不允許只靠你內建的知識作答。
    
    規則:
    - 如果沒有搜尋結果,請誠實說明。
    - 回答時,先列出你選定的關鍵字,再呈現答案。
    """
    
  • code
    agent = FunctionAgent(
        tools=tavily_tool_list,
        llm=OpenAI(model="gpt-5-mini"),
        system_prompt=system_prompt,
        streaming=False,
        verbose=True,
    )
    result = await agent.run(query)
    print("-----\nResult: ")
    print(result)
    
  • response
    • 結果他爆 call 了 search tool 8 次
    • 這邊就只截最後的response
    • https://ithelp.ithome.com.tw/upload/images/20250923/201778551b9lDDTaU6.jpg
    • 想要每句回答都像 perplexity 一樣有個 citation 可能還要更精細的控制
  1. 這邊看一下他到底都 call 了什麼
  • code
    for tool_call_result in result.tool_calls:
        print(f'tool_name: {tool_call_result.tool_name}')
        print(f'query: {tool_call_result.tool_kwargs}')
    
  • result
    tool_name: search
    query: {'query': 'definition of signs and symptoms medical', 'max_results': 6}
    tool_name: search
    query: {'query': 'definition of medical sign', 'max_results': 5}
    tool_name: search
    query: {'query': 'definition of medical sign', 'max_results': 5}
    tool_name: search
    query: {'query': 'signs vs symptoms definition', 'max_results': 5}
    tool_name: search
    query: {'query': 'examples of signs and symptoms medical examples', 'max_results': 6}
    tool_name: search
    query: {'query': 'definition of medical sign examples Medical News Today MedlinePlus', 'max_results': 5}
    tool_name: search
    query: {'query': 'definition of medical sign', 'max_results': 5}
    tool_name: search
    query: {'query': 'definition of symptom medical', 'max_results': 6}
    
    • 所以確實是會自己做到: 生出一些查詢的關鍵字 -> 查詢
  1. 我們再 prompt 他看可不可以總結出我們要的 (question, context, answer)
  • code
    prompt = """你是一個知識卡生成器。  
    請將輸入的資訊整理成三段,分別是:  
    1. # question (原始問題,保持簡潔明確)  
    2. # context (可協助用來回答原始問題的關鍵資訊,如原始問題中特殊名詞的定義)  
    3. # answer (最終整合的答案,盡可能一言以蔽之,否則條列清楚,避免多餘贅述)  
    
    請務必輸出成以下格式,不要額外加其他文字:
    
    # question
    {填入問題}
    
    # context
    {填入相關的關鍵資訊}
    
    # answer
    {填入條理清晰的答案}
    """
    
    from llama_index.core.llms import ChatMessage
    query = '徵象(Signs)及症狀(Symptoms)之區別?'
    messages_dict = [
        {'role': 'user', 'content': query},
        {'role': 'assistant', 'content': result},
        {'role': 'user', 'content': prompt}
    ]
    messages = [ChatMessage(**msg) for msg in messages_dict]
    
    response = llm.chat(messages)
    print(response)
    
  • response
    # question
    徵象(Signs)及症狀(Symptoms)之區別?
    
    # context
    - 症狀(Symptom):患者主觀感受或自述,無法由第三方直接測量或觀察,如疼痛、噁心、頭暈、疲倦、心悸等。  
    - 徵象(Sign):醫療人員或他人可客觀觀察或測量的發現,如發燒(體溫)、皮疹、腫脹、血壓、檢驗或影像結果。  
    - 臨床記錄:SOAP 中 S = 症狀(Subjective),O = 徵象(Objective)。  
    - 邊界:患者描述可見現象(如看到皮疹或血尿)為症狀;經醫師觀察或檢驗確認後成為徵象。
    
    # answer
    一言以蔽之:症狀 = 主觀(patient-reported);徵象 = 客觀(observer-或 test-detected)。  
    - 症狀例:疼痛、噁心、頭暈、疲倦、發冷感。  
    - 徵象例:體溫升高、血壓異常、皮疹、腹部壓痛、實驗室或影像異常。  
    - 臨床應用:醫師綜合症狀與徵象以鑑別診斷;病歷中症狀寫入 S,徵象寫入 O。  
    - 小提醒:患者自述的可見變化若經檢查確認即成徵象。
    
    • 除了 context 想要可以帶有真正的 citation 之外,對這個結果還算感到滿意

Summary

  • 我們今天試了 llama-index 封裝的 tavily 檢索工具
    • 直接檢索的原文很雜亂,可以插入一個模組整理
  • 然後把 tavily 做成 tool 給 gpt-5-mini 用
    • 他直接爆 call 8 次,也許後面我們土炮個 workflow 來精細的控制這個問題
    • 對於 citation 應該還需要加上別的機制才符合預期,不然現在的結果就是講說我這個不是亂生的我看了文章的
  • 最後我們再加上了一個總結的 llm 要他整理成 (question, context, answer)
  • 離我們的目標貌似近了一點,但又還有一大堆細節要改,阿阿阿...加油!

Reference


上一篇
Day7: perplexity api 初探 與 fact_ckecher 功能測試
系列文
阿,又是一個RAG9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言