### [AI / ML領域相關學習筆記入口頁面](https://hackmd.io/@YungHuiHsu/BySsb5dfp) #### [Deeplearning.ai GenAI/LLM系列課程筆記](https://learn.deeplearning.ai/) ##### GenAI - [Large Language Models with Semantic Search。大型語言模型與語義搜索 ](https://hackmd.io/@YungHuiHsu/rku-vjhZT) - [LangChain for LLM Application Development。使用LangChain進行LLM應用開發](https://hackmd.io/1r4pzdfFRwOIRrhtF9iFKQ) - [Finetuning Large Language Models。微調大型語言模型](https://hackmd.io/@YungHuiHsu/HJ6AT8XG6) ##### RAG - [Preprocessing Unstructured Data for LLM Applications。大型語言模型(LLM)應用的非結構化資料前處理](https://hackmd.io/@YungHuiHsu/BJDAbgpgR) - [Building and Evaluating Advanced RAG。建立與評估進階RAG](https://hackmd.io/@YungHuiHsu/rkqGpCDca) - [[GenAI][RAG] Multi-Modal Retrieval-Augmented Generation and Evaluaion。多模態的RAG與評估 ](https://hackmd.io/@YungHuiHsu/B1LJcOlfA) ##### AI Agents 原理可參考這篇綜論: [How Agents for LLM Perform Task Planning。大型語言模型的代理如何進行任務規劃](https://hackmd.io/@YungHuiHsu/rkK52BkQp) - 相關framework選擇 - [AI Agents in LangGraph](https://hackmd.io/@YungHuiHsu/BJTKpkEHC) - [Building Agentic RAG with LlamaIndex](https://learn.deeplearning.ai/courses/building-agentic-rag-with-llamaindex/lesson/1/introduction) - [Multi AI Agent Systems with crewAI](https://learn.deeplearning.ai/courses/multi-ai-agent-systems-with-crewai/lesson/1/introduction) - [Functions, Tools and Agents with LangChain](https://learn.deeplearning.ai/courses/functions-tools-agents-langchain/lesson/1/introduction) - Agent相關 - [Long-Term Agentic Memory With LangGraph](https://hackmd.io/@YungHuiHsu/S1f1cyOnke) --- --- # [Long-Term Agentic Memory With LangGraph](https://learn.deeplearning.ai/courses/long-term-agentic-memory-with-langgraph/lesson/ovv0p/introduction?courseName=long-term-agentic-memory-with-langgraph) * [Introduction to Agent Memory](https://hackmd.io/@YungHuiHsu/S1f1cyOnke) * [Baseline Email Assistant、Email Assistant with Semantic Memory](https://hackmd.io/@YungHuiHsu/ryOkald2kl) * [Email Assistant with Semantic + Episodic Memory](https://hackmd.io/@YungHuiHsu/r15H8kQTkx) * [Email Assistant with Semantic + Episodic + Procedural Memory](https://hackmd.io/@YungHuiHsu/ByDawymp1e) --- ## [LangGraph官網對Semantic Memory的介紹](https://langchain-ai.github.io/langgraph/concepts/memory/?ref=blog.langchain.dev#semantic-memory) :::info 🧠 語意記憶(Semantic Memory) **語意記憶**,在人類與 AI agent 中,指的是對特定事實與概念的長期記憶。 在人類身上,這可能包括在學校學到的知識、概念間的關聯等。而對於 AI agent 而言,語意記憶常用於**個人化應用**,例如記住使用者過去提供的事實或偏好,以便產生更相關的回應。 > 🔸 **注意**:不要把語意記憶(semantic memory)與「語意搜尋(semantic search)」混淆。 > - 語意記憶是心理學術語,指儲存知識與事實。 > - 語意搜尋則是一種透過「語意(意義)」找出相似內容的技術,常基於嵌入向量(embeddings)。 ::: - 語意記憶(Semantic Memory)建議的資料儲存結構 | 模式 | 👤 Profile 模式 | 📄 Collection 模式 | |------|------------------|----------------------| | 圖示 | ![Profile 模式](https://hackmd.io/_uploads/B1vGihwp1l.png) | ![Collection 模式](https://hackmd.io/_uploads/ByCDonDTye.png) | | 概念 | 一份持續更新的 JSON 文件,描述使用者或實體的屬性 | 多份小型文件,每筆文件代表一個具體記憶片段 | | 儲存格式 | 單一 Profile(如 JSON)<br>```{"name": "Alex", "language_preference": "Traditional Chinese"}``` | 多個記憶文件,獨立產生與擴充 | | 優點 | - 結構完整<br>- 易於掌握全貌 | - 易於更新<br>- 範圍小,產生簡單<br>- 對於新知識 的「召回率(recall)較高 | | 更新方式 | - 傳入舊 profile<br>- 模型輸出新 profile 或 JSON Patch | - 模型新增、刪除、更新文件 | | 挑戰 | - Profile 越大越難維護<br>- 結構易錯<br>- 需 schema 驗證 | - 需處理去重/合併問題<br>- 記憶查找成本高<br>- 缺乏整體脈絡 | | 適用工具 | JSON schema validation | Trustcall、LangSmith | --- ## 範例: Baseline Email Assistant 先建立基本的 Email Assistant架構,紅、綠、藍色的字體代表Memory的額外設計。 ![image](https://hackmd.io/_uploads/HkdDTx_nke.png) ![image](https://hackmd.io/_uploads/ByoRL-d2ke.png) ```python! from langgraph.graph import StateGraph, START, END from langgraph.types import Command from typing import Literal from IPython.display import Image, display email_agent = StateGraph(State) email_agent = email_agent.add_node(triage_router) email_agent = email_agent.add_node("response_agent", agent) email_agent = email_agent.add_edge(START, "triage_router") email_agent = email_agent.compile() ``` ```mermaid graph TD A[Start] --> B[Triage_Router Agent] B -->|IGNORE| E[End] B -->|NOTIFY| E B -->|RESPOND| C[Response Agent] %% Triage Router Prompt Integration K((Triage Prompt)) --> B M[triage_system_prompt] --> K N[triage_user_prompt] --> K subgraph Response_Agent C --> D[Agent Tools] D --> F[Write Email] D --> G[Schedule Meeting] D --> H[Check Calendar] end C --> E[End] %% Prompt 說明 B:::agent C:::agent K:::prompt %% Style Definitions classDef agent fill:#FFD700,stroke:#333,stroke-width:2px classDef prompt fill: #e6e6e6,stroke:#333,stroke-width:2px classDef tool fill:#87CEEB,stroke:#333,stroke-width:2px %% Apply Classes B:::agent C:::agent K:::prompt M:::prompt N:::prompt %% Apply subgraph styles style Response_Agent fill:transparent,stroke:#333,stroke-width:2px ``` ### Define the first part of the agent - triage. 根據 `Lesson 2_Baseline Email Assistant.ipynb` 中的段落 `## Define the first part of the agent - triage.`,以下是詳細的執行流程和參數的 mermaid 流程圖: #### `triage_router` ```python def triage_router(state: State) -> Command[ Literal["response_agent", "__end__"] ]: author = state['email_input']['author'] to = state['email_input']['to'] subject = state['email_input']['subject'] email_thread = state['email_input']['email_thread'] system_prompt = triage_system_prompt.format( full_name=profile["full_name"], name=profile["name"], user_profile_background=profile["user_profile_background"], triage_no=prompt_instructions["triage_rules"]["ignore"], triage_notify=prompt_instructions["triage_rules"]["notify"], triage_email=prompt_instructions["triage_rules"]["respond"], examples=None ) user_prompt = triage_user_prompt.format( author=author, to=to, subject=subject, email_thread=email_thread ) result = llm_router.invoke( [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ] ) if result.classification == "respond": print("📧 Classification: RESPOND - This email requires a response") goto = "response_agent" update = { "messages": [ { "role": "user", "content": f"Respond to the email {state['email_input']}", } ] } elif result.classification == "ignore": print("🚫 Classification: IGNORE - This email can be safely ignored") update = None goto = END elif result.classification == "notify": # If real life, this would do something else print("🔔 Classification: NOTIFY - This email contains important information") update = None goto = END else: raise ValueError(f"Invalid classification: {result.classification}") return Command(goto=goto, update=update) ``` - `triage_router` 的詳細工作流程: 1. **Start**: 開始處理電子郵件。 2. **Extract Email Details**: 提取電子郵件的詳細信息,包括作者、收件人、主題和郵件內容。 3. **Format System Prompt**: 格式化系統提示,填充用戶的詳細信息和分類規則。 4. **Format User Prompt**: 格式化用戶提示,填充郵件的詳細信息。 5. **Invoke LLM Router**: 調用 LLM 路由器,傳遞系統提示和用戶提示。 6. **Classification Result**: 根據 LLM 路由器的結果進行分類。 - **Respond**: 如果分類為回應,則生成回應內容,更新消息並轉到回應代理。 - **Ignore**: 如果分類為忽略,忽略消息並結束流程。 - **Notify**: 如果分類為通知,通知消息並結束流程。 7. **End**: 結束流程。 ### Main agent, define tools 根據程式碼段落 `## Main agent, define tools`,以下是詳細的執行流程和參數的 mermaid 流程圖: ```python @tool def write_email(to: str, subject: str, content: str) -> str: """Write and send an email.""" # 實際應用中會真的發送郵件 return f"Email sent to {to} with subject '{subject}'" @tool def schedule_meeting(attendees: list[str], subject: str, duration_minutes: int, preferred_day: str) -> str: """Schedule a calendar meeting.""" # 實際應用中會確認行事曆並安排會議 return f"Meeting '{subject}' scheduled for {preferred_day} with {len(attendees)} attendees" @tool def check_calendar_availability(day: str) -> str: """Check calendar availability for a given day.""" # 實際應用中會檢查真實的行事曆 return f"Available times on {day}: 9:00 AM, 2:00 PM, 4:00 PM" ``` mermaid 流程圖: ````mermaid graph TD A[Define Tools] --> B[Define write_email] B --> C[Input: to, subject, content] C --> D[Output: Email sent confirmation] A --> E[Define schedule_meeting] E --> F[Input: attendees, subject, duration_minutes, preferred_day] F --> G[Output: Meeting scheduled confirmation] A --> H[Define check_calendar_availability] H --> I[Input: day] I --> J[Output: Available times] classDef startEnd fill:#f9f,stroke:#333,stroke-width:2px; classDef process fill:#bbf,stroke:#333,stroke-width:2px; class A startEnd; class B,E,H process; class C,F,I process; class D,G,J process; ```` #### Main agent, define tools` 的詳細執行流程和參數: 1. **Define Tools**: 定義工具。 2. **Define write_email**: 定義 `write_email` 工具。 - **Input**: 接受 `to`(收件人)、`subject`(主題)和 `content`(內容)作為輸入參數。 - **Output**: 返回郵件發送確認信息。 3. **Define schedule_meeting**: 定義 `schedule_meeting` 工具。 - **Input**: 接受 `attendees`(參加者列表)、`subject`(主題)、`duration_minutes`(持續時間)和 `preferred_day`(首選日期)作為輸入參數。 - **Output**: 返回會議安排確認信息。 4. **Define check_calendar_availability**: 定義 `check_calendar_availability` 工具。 - **Input**: 接受 `day`(日期)作為輸入參數。 - **Output**: 返回可用時間信息。 ### prompts | Prompt 名稱 | 差異 | 輸入 | 輸出 | |-------------|------|------|------| | `agent_system_prompt` | 基本代理提示,包含基本工具 | `{full_name}`, `{name}`, `{instructions}` | 格式化的系統提示 || | `triage_system_prompt` | 分類郵件的提示,包含分類規則 | `{full_name}`, `{name}`, `{user_profile_background}`, `{triage_no}`, `{triage_notify}`, `{triage_email}`, `{examples}` | 格式化的系統提示,包含分類規則和示例 | | `triage_user_prompt` | 用戶提示,用於分類郵件 | `{author}`, `{to}`, `{subject}`, `{email_thread}` | 格式化的用戶提示,包含郵件詳細信息 | --- ## Email Assistant with Semantic Memory課程範例 :::success Semantic Memory實作:在Response Agent內加入事實/語意記憶的管理與查找功能(as tool),可以將使用者輪廓資料作為Prompt的一部分 ::: 在Response_Agent中加入`manage_memory_tool` 與`create_manage_memory_tool` ```PYTHON! tools= [ write_email, schedule_meeting, check_calendar_availability, manage_memory_tool, # 新增記憶管理工具 search_memory_tool # 新增記憶搜尋工具 ] ``` ```mermaid graph TD A[Start] --> B[Triage_Router Agent] B -->|IGNORE| E[End] B -->|NOTIFY| E B -->|RESPOND| C[Response Agent] %% Triage Router Memory and Prompt Integration K((Triage Prompt)) --> B M[triage_system_prompt] --> K N[triage_user_prompt] --> K subgraph Response_Agent C --> D[Agent Tools] D --> F[Origin Tools]:::tool subgraph Semantic_Memory_as_Tools[Semantic Memory_as_Tools ] I[manage_memory]:::tool J[search_memory]:::tool end D --> Semantic_Memory_as_Tools end %% Style Definitions classDef agent fill:#FFD700,stroke:#333,stroke-width:2px classDef prompt fill: #e6e6e6,stroke:#333,stroke-width:2px classDef tool fill:#87CEEB,stroke:#333,stroke-width:2px classDef storage fill:#FFFFFF,stroke:#333,stroke-width:2px classDef memory fill:#FFEFD5,stroke:#333,stroke-width:2px classDef semantic color:#000080,stroke:#333,stroke-width:2px classDef episodic color:#006400,stroke:#333,stroke-width:2px classDef subgraphStyle fill:#E8F5E9,stroke:#333,stroke-width:2px %% Apply Classes B:::agent C:::agent K:::prompt M:::prompt N:::prompt %% Apply subgraph styles style Semantic_Memory_as_Tools fill:#E8F5E9,stroke:#333,stroke-width:2px style Response_Agent fill:transparent,stroke:#333,stroke-width:2px ``` ### `langmem`的`create_manage_memory_tool()` 與 `create_search_memory_tool()` #### 🔹 **`manage_memory_tool()`** - 🔧 功能 此工具的目的是**將使用者的行為、互動、指示等資訊儲存在記憶系統中**,使 Email Assistant 在未來的互動中可以參考這些記憶來提供更個人化的回應。 ```python from langmem import create_manage_memory_tool, \ create_search_memory_tool manage_memory_tool = create_manage_memory_tool( namespace=( "email_assistant", "{langgraph_user_id}", "collection" ) ) ``` --- #### 🔹 **`create_search_memory_tool()`** - 🔧 功能 此工具的目的是**在記憶系統中搜尋與過往互動、郵件或行為相關的資料**,幫助 Email Assistant 根據過去的資訊提供更智慧的回應。 ```python= search_memory_tool = create_search_memory_tool( namespace=( "email_assistant", "{langgraph_user_id}", "collection" ) ) ``` | 功能/特性 | `manage_memory_tool()` | `search_memory_tool()` | |---------------------------|----------------------------------|----------------------------------| | **目的** | 儲存使用者資訊、行為或指示 | 搜尋使用者過去的資訊 | | **輸入參數 (Parameters)** | `memory_type`, `user`, `data_type`, `content` | `memory_type`, `user`, `data_type`, `query` | | **輸出 (Output)** | 儲存成功訊息或錯誤提示 | 搜尋結果或「無結果」提示 | | **應用場景 (Use Case)** | 儲存指示、行為偏好、個人化資訊 | 檢索過往郵件、過往指示或互動記錄 | #### 在`response_agent`中加入memory tool - 要注意的是`memory_tool`還是需要透過`InMemoryStore` 將儲存的記憶pass給agent ```python= from langgraph.store.memory import InMemoryStore store = InMemoryStore( index={"embed": "openai:text-embedding-3-small"} ) tools= [ write_email, schedule_meeting, check_calendar_availability, manage_memory_tool, search_memory_tool ] response_agent = create_react_agent( "anthropic:claude-3-5-sonnet-latest", tools=tools, prompt=create_prompt, # Use this to ensure the store is passed to the agent store=store ) ``` --- ### `agent_system_prompt` 與 `agent_system_prompt_memory` 的差異 ```PYTHON= # Agent prompt baseline agent_system_prompt = """ < Role > You are {full_name}'s executive assistant. You are a top-notch executive assistant who cares about {name} performing as well as possible. </ Role > < Instructions > {instructions} </ Instructions > """ # Agent prompt semantic memory agent_system_prompt_memory = """ ... < Tools > ... 4. manage_memory("email_assistant", user, "collection") - Store any relevant information about contacts, actions, discussion, etc. in memory for future reference 5. manage_memory("email_assistant", user, "user_profile") - Store any relevant information about the recipient, {name}, in the user profile for future reference the current user profile is shown below 6. search_memory("email_assistant", user, "collection") - Search memory for detail from previous emails 7. manage_memory("email_assistant", user, "instructions") - Update the instructions for agent tool usage based upon the user feedback </ Tools > ... ``` | 特點/功能 | `agent_system_prompt` | `agent_system_prompt_memory` | |----------------------------------------|----------------------------------------------|--------------------------------------------------| | **額外工具 (Memory Tools)** | ❌ 無額外的記憶管理工具。 | ✅ 4 個額外工具:<br>4. `manage_memory("collection")`<br>5. `manage_memory("user_profile")`<br>6. `search_memory("collection")`<br>7. `manage_memory("instructions")` | | **使用者檔案 (User Profile)** | ❌ 未包含 `profile` (用戶偏好、背景等個人化資訊)。 | ✅ 包含 `profile`,用於儲存使用者的背景、喜好與行為資訊。 | ---