Chuyển đến nội dung chính

第 15 課:AI 代理中的記憶、規劃與推理

記憶類型:短期(對話)、長期(向量儲存)、情境。规划策略:任务分解、子目标生成。鍊式思考推理。自我反思,迭代完善。人機互動模式。

**特工不像金魚那樣有記憶力 - 每次他們說話時,他們就會忘記一切。 ** 不知道如何計劃的特工只會胡亂行動。不懂推理的特工只能“鹦鹉学舌”地模仿提示。 记忆、规划、推理这三种功能将简单的聊天机器人变成真正的智能人工智能代理。在本文中,我們將深入研究每項能力,用 LangChain、LangGraph、Redis、PostgreSQL 來實現它,然後將其合成為一個能夠記憶、規劃和推理的完整代理。


1. 為什麼記憶很重要?

1.1。沒有記憶的特務=金魚

想像一下,您每天都會打電話,但它不記得任何事情:

Ngày 1: "Tôi thích Python, đang học AI"
Agent:  "Tuyệt vời! Tôi sẽ giúp bạn học AI với Python."

Ngày 2: "Tiếp tục bài hôm qua đi"
Agent:  "Xin lỗi, bạn là ai? Bạn muốn học gì?"  ← 🐟 Goldfish mode

Ngày 3: "Nhắc lại preferences của tôi"
Agent:  "Tôi không có thông tin gì về bạn."      ← 🐟🐟🐟

這是核心問題:LLM 設計為無狀態。每個 API 呼叫都是一個新的對話。如果沒有記憶層,代理就會失去所有上下文。

1.2。上下文視窗 - 硬限制

每个法学硕士都有一个有限的上下文窗口:

型號上下文視窗~文字頁數
GPT-4o128K 代幣約 300 頁
克勞德 3.5 十四行詩20 萬個代幣約 500 頁
雙子座1.5 Pro2M 代幣約 5000 頁
駱駝3.1128K 代幣約 300 頁

聽起來很多,但在生產中:

Context Window Budget (128K tokens):
┌──────────────────────────────────────┐
│ System prompt          ~2K tokens    │
│ Tool definitions       ~5K tokens    │
│ Conversation history   ~40K tokens   │  ← Tăng nhanh!
│ Retrieved documents    ~30K tokens   │
│ Current task context   ~10K tokens   │
│ ─────────────────────────────────    │
│ Còn lại cho response   ~41K tokens   │
│                                      │
│ ⚠️  Sau 50 lượt chat → overflow!     │
└──────────────────────────────────────┘

記憶體層幫助代理有效地管理資訊,而不是將其全部塞入上下文視窗中。

1.3。三元能力:記憶-計畫-推理

                    ┌─────────────────┐
                    │   AI AGENT      │
                    │   Intelligence  │
                    └────────┬────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
        ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
        │  MEMORY   │ │ PLANNING  │ │ REASONING │
        │           │ │           │ │           │
        │ Nhớ quá   │ │ Lập kế    │ │ Suy luận  │
        │ khứ, học  │ │ hoạch,    │ │ logic,    │
        │ từ kinh   │ │ phân      │ │ giải      │
        │ nghiệm    │ │ rã task   │ │ thích     │
        └───────────┘ └───────────┘ └───────────┘
              │              │              │
              └──────────────┼──────────────┘
                             │
                    ┌────────▼────────┐
                    │ Intelligent     │
                    │ Action          │
                    └─────────────────┘

提示: 这三种能力不能独立发挥作用。記憶為規劃提供了背景。規劃為推理創建結構。推理改善了智能體使用記憶體的方式。這是一個良性循環。


2. AI Agent 中的記憶體類型

2.1。記憶體的分類

AI Agent 需要許多不同類型的記憶,類似於人腦的工作方式:

Human Brain Analogy → AI Agent Memory

┌─────────────────────────────────────────────────────────┐
│                    MEMORY SYSTEM                         │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │  Short-term  │  │  Long-term   │  │   Working    │  │
│  │   Memory     │  │   Memory     │  │   Memory     │  │
│  │              │  │              │  │              │  │
│  │ Conversation │  │ Vector Store │  │ Current task │  │
│  │ buffer,      │  │ Knowledge    │  │ scratchpad,  │  │
│  │ last N turns │  │ base, facts  │  │ intermediate │  │
│  │              │  │              │  │ results      │  │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  │
│         │                 │                 │           │
│  ┌──────▼───────┐  ┌──────▼───────┐                    │
│  │  Episodic    │  │  Semantic    │                    │
│  │   Memory     │  │   Memory     │                    │
│  │              │  │              │                    │
│  │ Past events, │  │ Concepts,    │                    │
│  │ experiences, │  │ relationships│                    │
│  │ success/fail │  │ world know.  │                    │
│  └──────────────┘  └──────────────┘                    │
└─────────────────────────────────────────────────────────┘

2.2。內存類型對照表

內存類型堅持產能使用案例範例
短期僅限會議小(最後 N 圈)對話背景聊天記錄緩衝區
長期永久大(無限制)知識保留向量存儲,DB
情境永久平均汲取經驗“上次使用者討厭 X 格式”
語意永久大事實與概念“Python 是一種程式語言”
工作任務持續時間小當前任務狀態暫存器,中間結果

2.3。短期記憶——對話緩衝

短期記憶保留了最近的對話內容:

Conversation Buffer Memory:

  Turn 1: User: "Tìm giá Bitcoin hôm nay"
  Turn 2: Agent: "BTC = $67,500"            ← Lưu lại
  Turn 3: User: "So sánh với tuần trước"
  Turn 4: Agent: "Tuần trước $65,200,       ← Dùng context
                   tăng 3.5%"                   từ Turn 2
  Turn 5: User: "Dự đoán tuần tới"
  Turn 6: Agent: "Dựa trên trend..."        ← Dùng cả
                                                Turn 2+4

Sliding Window (keep last K turns):

  K=4: [Turn 3, Turn 4, Turn 5, Turn 6]     ← Turn 1-2 bị cắt
  K=6: [Turn 1, Turn 2, ..., Turn 6]        ← Giữ hết

2.4。長期記憶 — 向量存儲

長期記憶永久儲存訊息,通常使用向量資料庫:

Long-term Memory Flow:

  User input → Embedding → Query Vector DB
                               │
                    ┌──────────▼──────────┐
                    │   Vector Store      │
                    │                     │
                    │  📄 "User thích     │
                    │      Python, AI"    │
                    │  📄 "Đã hoàn thành  │
                    │      project X"     │
                    │  📄 "Prefer dark    │  ← Similarity
                    │      theme, brief   │     search
                    │      responses"     │
                    │  📄 "Works at       │
                    │      Company Y"     │
                    └──────────┬──────────┘
                               │
                    Top-K relevant memories
                               │
                    ┌──────────▼──────────┐
                    │  Inject into prompt │
                    └─────────────────────┘

2.5。情景記憶與語意記憶

方面情景記憶語意記憶
內容具體事件/情節一般事實/概念
格式“X 天,使用者要求 Y,代理執行 Z,結果 W”“Python 使用縮排而不是大括號”
檢索依時間/上下文相似度依概念相似度
更新追加新劇集合併與更新事實
用例從過去的錯誤中學習建立知識庫

提示:情景記憶對於自我提升極為重要。 Agent記住「上次使用策略A失敗,策略B成功」→下次選擇B。


3. 使用 Python 實作代理內存

3.1。浪鏈內存類

LangChain提供了許多內建的記憶體類別:

from langchain.memory import (
    ConversationBufferMemory,
    ConversationBufferWindowMemory,
    ConversationSummaryMemory,
    ConversationSummaryBufferMemory,
    VectorStoreRetrieverMemory,
)
from langchain_openai import ChatOpenAI

# 1. Buffer Memory — Giữ nguyên toàn bộ history
buffer_memory = ConversationBufferMemory(
    memory_key="chat_history",
    return_messages=True,  # Return dạng Message objects
)

# 2. Window Memory — Chỉ giữ K turns gần nhất
window_memory = ConversationBufferWindowMemory(
    k=10,  # Giữ 10 lượt gần nhất
    memory_key="chat_history",
    return_messages=True,
)

# 3. Summary Memory — Tóm tắt history bằng LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
summary_memory = ConversationSummaryMemory(
    llm=llm,
    memory_key="chat_history",
    return_messages=True,
)

# 4. Summary Buffer — Hybrid: summary cũ + buffer mới
summary_buffer = ConversationSummaryBufferMemory(
    llm=llm,
    max_token_limit=2000,  # Summarize khi vượt limit
    memory_key="chat_history",
    return_messages=True,
)

比較記憶體類別:

內存類別代幣使用資訊遺失最適合
ConversationBufferMemory線性增加無損失短聊(<20 turns)
ConversationBufferWindowMemory固定(K 圈)失去舊轉彎聊了很長時間,只需要最近的上下文
ConversationSummaryMemory緩慢增長丟失細節聊了很長時間,需要概述
ConversationSummaryBufferMemory混合動力減少損失生產-最佳平衡

3.2. Vector Store-backed Memory

使用向量儲存來儲存長期記憶,以幫助代理記住跨會話的資訊:

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.memory import VectorStoreRetrieverMemory
import chromadb

# Setup vector store
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(
    collection_name="agent_memory",
    embedding_function=embeddings,
    persist_directory="./memory_store",
)

# Tạo retriever memory
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
vector_memory = VectorStoreRetrieverMemory(
    retriever=retriever,
    memory_key="relevant_history",
    input_key="input",
)

# Lưu memory
vector_memory.save_context(
    inputs={"input": "Tôi đang làm project e-commerce bằng FastAPI"},
    outputs={"output": "Tuyệt! FastAPI rất phù hợp cho e-commerce API."},
)

vector_memory.save_context(
    inputs={"input": "Database tôi dùng PostgreSQL với SQLAlchemy"},
    outputs={"output": "PostgreSQL + SQLAlchemy là combo mạnh mẽ."},
)

# Query — tự động retrieve relevant memories
result = vector_memory.load_memory_variables(
    {"input": "Giúp tôi optimize database queries"}
)
print(result["relevant_history"])
# → Trả về memories liên quan đến PostgreSQL, SQLAlchemy

3.3。 Redis 持久記憶體

使用 Redis 來在重新啟動後保留記憶體:

from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain.memory import ConversationBufferMemory
from langchain_openai import ChatOpenAI
from langchain.chains import ConversationChain

# Redis-backed message history
message_history = RedisChatMessageHistory(
    session_id="user_123_session_456",
    url="redis://localhost:6379/0",
    ttl=86400 * 7,  # 7 ngày expiry
)

# Wrap trong ConversationBufferMemory
redis_memory = ConversationBufferMemory(
    memory_key="chat_history",
    chat_memory=message_history,
    return_messages=True,
)

# Dùng trong chain
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
conversation = ConversationChain(
    llm=llm,
    memory=redis_memory,
    verbose=True,
)

# Chat — memory persist qua Redis
response = conversation.predict(input="Tôi tên Minh, đang học AI")
# Restart app → memory vẫn còn trong Redis
response = conversation.predict(input="Tôi tên gì?")
# → "Bạn tên Minh"

3.4. Custom Memory Manager — Production Pattern

在生產中,我們經常需要一個結合了多種記憶體類型的自訂記憶體管理器:

from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
import json

from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma


@dataclass
class MemoryEntry:
    content: str
    memory_type: str  # short_term, long_term, episodic, semantic
    timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
    metadata: dict = field(default_factory=dict)
    importance: float = 0.5  # 0.0 - 1.0


class AgentMemoryManager:
    """Unified memory manager kết hợp nhiều memory types."""

    def __init__(self, user_id: str, persist_dir: str = "./agent_memory"):
        self.user_id = user_id
        self.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
        self.llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

        # Short-term: conversation buffer
        self.short_term: list[dict] = []
        self.max_short_term = 20

        # Long-term: vector store
        self.long_term = Chroma(
            collection_name=f"long_term_{user_id}",
            embedding_function=self.embeddings,
            persist_directory=f"{persist_dir}/{user_id}/long_term",
        )

        # Episodic: vector store riêng
        self.episodic = Chroma(
            collection_name=f"episodic_{user_id}",
            embedding_function=self.embeddings,
            persist_directory=f"{persist_dir}/{user_id}/episodic",
        )

    def add_short_term(self, role: str, content: str):
        """Thêm vào short-term buffer."""
        self.short_term.append({
            "role": role,
            "content": content,
            "timestamp": datetime.now().isoformat(),
        })
        # Sliding window
        if len(self.short_term) > self.max_short_term:
            # 刪除前總結最舊的訊息
            self._summarize_and_archive(self.short_term[:5])
            self.short_term = self.short_term[5:]

    def add_long_term(self, 內容: str, 元資料: 可選[dict] = None):
        """將事實/偏好保存到長期記憶中。"""
        元 = 元資料或 {}
        元[“user_id”] = self.user_id
        元[“時間戳記”] = datetime.now().isoformat()
        元[“類型”] =“長期”
        self.long_term.add_texts(
            文本=[內容],
            元資料=[元],
        )

    def add_episode(self, 任務: str, 動作: list[str],
                    結果:str,成功:bool):
        “”“保存情節(經驗)以從過去學習。”“”
        劇集文字 = (
            f"任務:{任務}\n"
            f"動作:{', '.join(actions)}\n"
            f"結果:{結果}\n"
            f“成功:{成功}”
        )
        self.episodic.add_texts(
            文本=[劇集文本],
            元資料=[{
                「任務」:任務,
                「成功」:成功,
                「時間戳記」:datetime.now().isoformat(),
                “類型”:“情景”,
            }],
        )

    def recall(self, query: str, k: int = 5) -> dict:
        “”“回憶所有商店的相關記憶。”“”
        # 短期:返回全部(受滑動視窗限制)
        Short = self.short_term[-10:] # 最後 10 回合

        # 長期:相似性搜尋
        長 = self.long_term.similarity_search(查詢, k=k)

        # Episodic:尋找相關的過去經歷
        劇集 = self.episodic.similarity_search(query, k=3)

        返回{
            「短期」:短期,
            "long_term": [long 文件的 doc.page_content],
            "episodic": [doc.page_content 用於劇集中的文件],
        }

    def _summarize_and_archive(self, messages: list[dict]):
        """總結舊消息並長期保存。"""
        文字 = "\n".join(
            f"{m['role']}: {m['content']}" 表示訊息中的 m
        )
        摘要 = self.llm.invoke(
            f“簡潔地總結一下這次對話:\n{text}”
        )
        self.add_long_term(
            內容=摘要.內容,
            元資料={"type": "conversation_summary"},
        )


#用法
記憶體 = AgentMemoryManager(user_id="user_123")

#對話
memory.add_short_term("user", "我需要為銷售應用程式建立 REST API")
memory.add_short_term("assistant", "我建議使用FastAPI + PostgreSQL")
memory.add_long_term("使用者需要REST API進行電子商務,偏好FastAPI")

# 記錄劇集
記憶體.add_episode(
    任務=“為產品建立CRUD API”,
    actions=["建立 FastAPI 應用程式", "新增 SQLAlchemy 模型", "編寫測試"],
    result="API 測試覆蓋率為 100%",
    成功=真,
)

# 稍後-回憶相關上下文
context = memory.recall("如何優化API效能?")

提示: 在製作中,將 重要性評分 加入記憶中。並非所有資訊都需要保存。在保存到長期記憶之前使用 LLM 評估重要性。


4. Planning Strategies

4.1。為什麼代理商需要規劃?

不知道規劃的智能體將會表現出反應性-只是對當前的輸入做出反應,而沒有策略。規劃使代理變得主動-能夠根據策略進行規劃和執行。

無計劃: 有計劃:

使用者:“寫一篇關於人工智慧的部落格文章” 用戶:“寫一篇關於人工智慧的部落格文章”
                                   
代理人:*立即寫信* 代理人思考:
       *忘記研究* 1. 研究人工智慧熱門話題
       *無大綱* 2.選擇主題+建立大綱
       *缺少範例* 3. 根據大綱寫草稿
       *混亂的結果* 4.新增程式碼範例
                                    5. 審核和編輯
                                    6. 格式化和定稿
                                   
                                   代理:*執行每一步*
                                          *結構化結果*

4.2. Task Decomposition

任務分解是一種將複雜任務分解為更小、易於處理的子任務的技術:

任務分解流程:

  複雜的任務:“分析競爭對手並制定行銷策略”
                              │
                    ┌──────────▼──────────┐
                    │ 分解器 │
                    │ (法學碩士) │
                    └──────────┬──────────┘
                              │
         ┌──────────────────── ┼────────────────────┐
         │ │ │
  ┌──────▼──────┐ ┌────────▼──────┐ ┌──────▼────┐
  │ 子任務 1 │ │ 子任務 2 │ │ 子任務 3 │
  │ │ │ │ │ │
  │ 研究 │ │ SWOT │ │ 創造 │
  │ 競爭對手 │──→ │ 分析 │──→ │ 策略 │
  │(網路搜尋)│ │(分析)│ │(撰寫文件)│
  └──────────────┘ └──────────────┘ └────────────┘
         │ │ │
         ▼ ▼ ▼
    5 個 SWOT 矩陣策略文件列表
    每個競爭對手的行動

Implementation:

從 langchain_openai 導入 ChatOpenAI
從 langchain_core.prompts 導入 ChatPromptTemplate
從 pydantic 匯入 BaseModel、Field


類別子任務(基礎模型):
    “”“計劃中的子任務。”“”
    id: int = Field(描述=“任務 ID”)
    描述:str = Field(描述=“子任務描述”)
    依賴項:列表[int] = Field(
        default_factory = list,description =“這取決於任務的ID”
    )
    需要的工具:列表[str]=欄位(
        default_factory=列表,描述=“所需工具”
    )


類別任務計劃(基礎模型):
    “”“計劃分解任務。”“”
    目標:str = Field(描述=“總體目標”)
    子任務:list[SubTask] = Field(description="子任務清單")
    估計步數:int = Field(描述=“總步數”)


llm = ChatOpenAI(模型=“gpt-4o”,溫度=0)
Structured_llm = llm.with_structed_output(任務計劃)

decompose_prompt = ChatPromptTemplate.from_messages([
    (「系統」,「」「你是任務規劃專家。
將使用者的複雜任務分解為更小的、可操作的子任務。
每個子任務應該是:
- 具體且可操作
- 有明確的依賴關係
- 列出所需的工具

可用工具:web_search、code_executor、file_writer、
                 資料分析器、文件產生器"""),

    (“人類”,“任務:{任務}”),
])

鏈結= decompose_prompt |結構化_llm

#分解
計劃 = chain.invoke({
    "task": "分析EdTech領域的3個競爭對手"
            “並產生詳細的比較報告”
})

對於 plan.subtasks 中的子任務:
    deps = f" (取決於: {subtask.dependency})" if subtask.dependency else ""
    print(f" [{subtask.id}] {subtask.description}{deps}")
    print(f" 工具: {subtask.tools_needed}")

4.3. Plan-and-Execute Pattern

計劃並執行是最強大的模式:代理首先創建計劃,然後執行每個步驟。如果任何步驟失敗,代理可以重新計劃。

計劃和執行循環:

  ┌──────────┐
  │ 輸入 │
  │ (複雜 │
  │ 任務) │
  └──────┬──────┘
         │
  ┌──────▼──────┐ ┐──────────────┐
  │ 計畫者 │────→ 計畫 │
  │ (建立 │ │ [步驟 1, │
  │ 計畫) │ │ 步驟2, │
  └──────────────┘ │ 步驟3,...] │
                      └──────┬────────┘
                             │
                      ┌──────▼────────┐
                      │ 執行人 │
                      │(運行步驟)│◄────────────┐
                      └──────┬────────┘ │
                             │ │
                      ┌──────▼────────┐ ┌──────┴──────┐
                      │ 評估 │──否──│ 重新規劃 │
                      │ 成功?    │ │ (調整 │
                      └──────┬────────┘ │ 計畫) │
                             │是└────────────┘
                      ┌──────▼────────┐
                      │ 結果 │
                      └────────────┘

LangGraph implementation:

從輸入匯入 Annotated、TypedDict
從 langgraph.graph 匯入 StateGraph,END
從 langchain_openai 導入 ChatOpenAI
從 langchain_core.messages 導入 HumanMessage、SystemMessage


類別 PlanExecuteState(TypedDict):
    輸入:str
    計劃:列表[str]
    目前步數:整數
    步驟結果:清單[str]
    最終結果:str
    錯誤計數:整數


llm = ChatOpenAI(模型=“gpt-4o”,溫度=0)


def planner(狀態: PlanExecuteState) -> PlanExecuteState:
    """根據輸入建立計劃。"""
    響應 = llm.invoke([
        系統訊息(內容=(
            “你是一個計劃者。將任務分成 3-7 個具體步驟。”
            “僅返回編號清單。”
        )),
        HumanMessage(content=f"任務:{state['input']}"),
    ])
    步驟= [
        line.strip().lstrip("0123456789.").strip()
        對於response.content.strip().split("\n")中的行
        if line.strip()
    ]
    回傳{**狀態,「計畫」:步驟,「current_step」:0,「step_results」:[]}


def 執行器(狀態: PlanExecuteState) -> PlanExecuteState:
    """執行目前步驟。"""
    步驟=狀態[“計劃”][狀態[“目前步驟”]]
    上下文 = "\n".join(
        f“第{i+1}步結果:{r}”
        for i, r in enumerate(state["step_results"])
    )
    響應 = llm.invoke([
        系統訊息(內容=(
            “執行給定的步驟。使用前面步驟中的上下文。”
        )),
        人類留言(內容=(
            f"總體目標:{state['input']}\n"
            f"之前的結果:\n{context}\n"
            f"當前步驟:{步驟}\n"
            “執行這一步,返回結果。”
        )),
    ])
    結果 = 狀態["step_results"] + [response.content]
    返回{
        **狀態,
        “step_results”:結果,
        「當前步」:狀態[「當前步」] + 1,
    }


def should_continue(state: PlanExecuteState) -> str:
    """檢查是否還有其他步驟。"""
    如果狀態[“current_step”] >= len(狀態[“計劃”]):
        返回“最終確定”
    返回“執行”


def 終端機(狀態: PlanExecuteState) -> PlanExecuteState:
    “”“總結結果。”“”
    all_results = "\n\n".join(
        f“第{i+1}步:{r}”
        for i, r in enumerate(state["step_results"])
    )
    響應 = llm.invoke([
        SystemMessage(content="綜合所有步驟結果為最終答案。"),
        人類留言(內容=(
            f"目標:{狀態['輸入']}\n\n結果:\n{all_results}"
        )),
    ])
    返回{**state,“final_result”:response.content}


# 建立圖表
圖=狀態圖(計劃執行狀態)
graph.add_node("規劃器", 規劃器)
graph.add_node("執行器", 執行器)
graph.add_node("終結器", 終結器)

graph.set_entry_point("規劃器")
graph.add_edge("規劃者", "執行者")
graph.add_conditional_edges("執行者", should_continue, {
    “執行”:“執行者”,
    "finalize": "終結器",
})
graph.add_edge("終結器", END)

應用程式 = graph.compile()

# 運行
結果 = app.invoke({
    "input": "研究總結2025年人工智慧三大趨勢",
    「計劃」:[],
    「目前步數」:0,
    “步驟結果”:[],
    “最終結果”:“”,
    “錯誤計數”:0,
})
列印(結果[“最終結果”])

4.4. Hierarchical Planning

分層規劃:高層規劃 → 中階規劃 → 低階行動:

分層規劃:

0 級-戰略:
  《打造電子商務平台》
         │
1 級-戰術:
  ├── 「設計資料庫架構」
  ├── 「建構 REST API」
  ├── 「創建前端」
  └── 「設定展開」
         │
2 級 — 運行:
  ├── 「設計資料庫架構」
  │ ├── “定義產品模型”
  │ ├── “定義訂單模型”
  │ ├── “定義使用者模型”
  │ └── 「建立關係」
  ├── 「建構 REST API」
  │ ├── “安裝FastAPI專案”
  │ ├── 「實現 CRUD 端點」
  │ ├── 「新增認證」
  │ └── 「編寫API測試」
  …

提示: 分層規劃與 多代理系統 結合使用時特別有效(第 14 課)。代理經理處理 0-1 級,專業代理處理 2 級。


5. Chain-of-Thought Reasoning

5.1. CoT Prompting

**思想鏈(CoT)**迫使LLM逐步推理,而不是直接跳到結論:

無 CoT: 有 CoT:

問:“伺服器錯誤503,如何修復?” 問:“伺服器錯誤503,如何修復?”

A:「重啟伺服器」 A:「我們來分析一下每一步:
    (缺乏推理) 1. 503 = 服務不可用
                                           2、可能原因:
                                              - 後端服務關閉
                                              - 資源耗盡
                                              - 負載平衡器逾時
                                           3、需要檢查:
                                              - 伺服器日誌
                                              - CPU/記憶體使用情況
                                              - 上游服務
                                           4. 根據原因進行修復:
                                              - 擴大資源規模
                                              - 如果崩潰則重新啟動
                                              - 如果依賴則修復上游”

在代理程式中部署 CoT:

從 langchain_openai 導入 ChatOpenAI
從 langchain_core.prompts 導入 ChatPromptTemplate

llm = ChatOpenAI(模型=“gpt-4o”,溫度=0)

cot_prompt = ChatPromptTemplate.from_messages([
    (“系統”,“”“你是一位解決問題的專家。
對於每個問題,請遵循以下推理過程:

1. **理解**:用自己的話重述問題
2. **分析**:確定關鍵因素和限制因素
3. **分解**:如果複雜則分解為子問題
4. **原因**:逐步解決每個子問題
5. **綜合**:將子答案組合成最終答案
6. **驗證**:檢查答案是否有意義

使用以下格式清楚地表達你的推理:
[理解]...
[分析]...
[原因] ...
[答案] ..."""),
    (“人類”,“{問題}”),
])

鏈= cot_prompt |勒姆
響應 = chain.invoke({
    "question": "尖峰時段電商系統速度較慢。"
                “資料庫CPU 95%,API回應時間5s。解決方案嗎?”
})
列印(響應.內容)

5.2. Tree-of-Thought (ToT)

思想樹透過並行探索多個推理分支來擴展 CoT,然後選擇最好的一個:

思想樹:

                    問題
                       │
            ┌──────────┼──────────┐
            │ │ │
        想法 1 想法 2 想法 3
        “擴展資料庫”“新增快取”“優化
            │ │ 查詢》
         ┌──┴──┐ ┌──┴──┐ │
         │ │ │ │ │
       T1.1 T1.2 T2.1 T2.2 T3.1
       讀取新增Redis CDN索引
       副本 pgbouncer 靜態慢
                                      查詢
            │ │ │
         分數: 分數: 分數:
          0.7 0.9 0.8
            │ │ │
            └──────────┼──────────┘
                       │
                  最佳:思考2
                  》新增Redis快取+
                   CDN 靜態”
從 langchain_openai 導入 ChatOpenAI
從 langchain_core.messages 導入 HumanMessage、SystemMessage

llm = ChatOpenAI(模型=“gpt-4o”,溫度=0.7)
評估器= ChatOpenAI(模型=“gpt-4o”,溫度= 0)


def tree_of_thought(問題: str, n_thoughts: int = 3) -> str:
    “”“思想樹推理。”“”

    # 第 1 步:產生多個初始想法
    想法=[]
    對於我在範圍內(n_thoughts):
        響應 = llm.invoke([
            系統訊息(內容=(
                f“生成方法#{i+1}(與其他方法不同)”
                f“解決這個問題。要具體且有創意。”
            )),
            HumanMessage(content=f"問題:{問題}"),
        ])
        ideas.append(回應.內容)

    # 第 2 步:評估每個想法
    分數 = []
    對於思想中的思想:
        eval_response = evaluator.invoke([
            系統訊息(內容=(
                “按照 1-10 的等級評估該解決方案。”
                “考慮:可行性、有效性、成本、時間。”
                “僅傳回數字分數。”
            )),
            人類留言(內容=(
                f"問題:{問題}\n方法:{想法}"
            )),
        ])
        嘗試:
            分數 = float(eval_response.content.strip())
        除了值錯誤:
            分數 = 5.0
        分數.append(分數)

    # 第三步:選擇最佳想法並詳細闡述
    best_idx = Scores.index(max(分數))
    best_thought = 想法[best_idx]

    最終 = llm.invoke([
        系統訊息(內容=(
            “詳細說明此解決方案方法。提供詳細資訊”
            “實施步驟、潛在問題和緩解措施。”
        )),
        人類留言(內容=(
            f“問題:{問題}\n”
            f“所選方法(得分 {scores[best_idx]}/10):\n”
            f“{最佳想法}”
        )),
    ])

    返回最終內容


#用法
解決方案=思想樹(
    “電子商務應用程式需要處理黑色星期五期間 10 倍的流量高峰。”
    “當前堆疊:AWS 上的 FastAPI + PostgreSQL + Redis。”
)
列印(解決方案)

5.3. Self-Consistency

自洽產生多個推理路徑,然後選擇出現次數最多的答案(多數投票):

自洽流程:

  問題:“對於用戶配置文件,我應該使用 SQL 還是 NoSQL?”
                        │
           ┌────────────┼────────────┐
           │ │ │
       路徑 1 路徑 2 路徑 3
       (溫度=0.7) (溫度=0.7) (溫度=0.7)
           │ │ │
       “SQL 因為”SQL 因為“NoSQL 因為
        結構化ACID,靈活
        數據,ACID”加入“模式”
           │ │ │
           ▼ ▼ ▼
        答案:SQL 答案:SQL 答案:NoSQL
           │ │ │
           └────────────┼────────────┘
                        │
                 多數投票:SQL (2/3)
                 信賴度:66.7%

提示: 自我一致性對於決策任務特別有用。當智能體需要做出重要決策(選擇架構、選擇工具)時,產生5條推理路徑,然後投票選出更可靠的結果。


6. Self-Reflection & Iterative Refinement

6.1. Reflexion Architecture

反射是一種允許代理人自我評估輸出、從經驗中學習並改進的架構:

反射循環:

  ┌────────────────────────────────────────────┐
  │ │
  │ ┌──────────┐ ┌──────────┐ │
  │ │ 演員 │────→ 行動 │ │
  │ │ (代理) │ │ (執行) │
  │ └──────────┘ └────┬──────┘ │
  │ ▲ │ │
  │ │ ┌────▼──────┐ │
  │ │ │ 評估 │ │
  │ │ │ (檢查 │ │
  │ │ │ 結果) │ │
  │ │ └────┬──────┘ │
  │ │ │ │
  │ │ ┌────────▼──────────┐ │
  │ │ │ 反射鏡 │ │
  │ │ │ │ │
  │ │ │ 「出了什麼問題?」 │ │
  │ │ │ 「需要改進什麼?」 │ │
  │ │ │ 「吸取教訓?」 │ │
  │ │ └──────────┬──────────┘ │
  │ │ │ │
  │ │ ┌────────▼──────────┐ │
  │ │ │ 記憶體更新 │ │
  │ │ │ 儲存反射 │ │
  │ └────│ 下次試試 │ │
  │ └──────────────────────┘ │
  │ │
  └────────────────────── ──────────────────────┘

6.2. Self-Critique Loop — Implementation

從 langchain_openai 導入 ChatOpenAI
從 langchain_core.messages 導入 HumanMessage、SystemMessage
從 pydantic 匯入 BaseModel、Field


CritiqueResult 類別(基礎模型):
    分數: float = Field(description="質量分數 0-10")
    問題:list[str] = Field(description="發現問題")
    建議:list[str] = Field(description="改進建議")
    is_acceptable: bool = Field(description="輸出是否符合品質標準")


SelfRefiningAgent 類別:
    “”“具有自我批判和迭代完善的Agent。”“”

    def __init__(self, max_iterations: int = 3):
        self.actor = ChatOpenAI(model="gpt-4o", 溫度=0.7)
        self.critic = ChatOpenAI(model="gpt-4o", 溫度=0)
        self.structured_critic = self.critic.with_structured_output(CritiqueResult)
        self.max_iterations = max_iterations
        self.reflections: 列表[str] = []

    def生成(自我,任務:str)-> str:
        """產生初始輸出。"""
        上下文=“”
        如果自我反思:
            上下文 = (
                “\n\n之前的反思(避免這些錯誤):\n”
                + "\n".join(f"- {r}" for self.reflections 中的 r)
            )

        回應 = self.actor.invoke([
            系統訊息(內容=(
                “你是一位專家助理。產出高品質的成果。”
                f“{上下文}”
            )),
            HumanMessage(內容=任務),
        ])
        回傳回應內容

    def Critique(self, 任務: str, 輸出: str) -> CritiqueResult:
        “”“自我批評輸出。”“”
        返回 self.structed_critic.invoke([
            系統訊息(內容=(
                “您是嚴格的品質審核員。評估輸出”
                “違反任務要求。批評但公平。”
                “8分以上意味著品質可以接受。”
            )),
            人類留言(內容=(
                f“任務:{任務}\n\n要審核的輸出:\n{輸出}”
            )),
        ])

    def 反射(自我,任務:str,輸出:str,
                批評: CritiqueResult) -> str:
        “”“產生改進的反思。”“”
        反應 = self.critic.invoke([
            系統訊息(內容=(
                “根據批評,產生簡潔的反思”
                “這將有助於改進下一次嘗試。”
                “專注於具體的、可操作的改進。”
            )),
            人類留言(內容=(
                f"任務:{任務}\n"
                f“輸出:{輸出}\n”
                f“問題:{critique.issues}\n”
                f“建議:{critique.suggestions}”
            )),
        ])
        回傳回應內容

    def run(self, 任務: str) -> 字典:
        “”“運行自我優化循環。”“”
        對於範圍內的迭代(self.max_iterations):
            print(f"\n--- 迭代 {迭代 + 1} ---")

            # 生成
            輸出 = self.generate(任務)

            # 批評
            批判 = self.critique(任務, 輸出)
            print(f"分數:{critique.score}/10")
            print(f"可接受:{critique.is_acceptable}")

            如果 critique.is_acceptable:
                返回{
                    “輸出”:輸出,
                    「迭代」:迭代+1,
                    「final_score」:批評.score,
                }

            # 反映並存儲
            反射 = self.reflect(任務、輸出、批評)
            self.reflections.append(反射)
            print(f"反射:{反射[:100]}...")

        # 在最大迭代次數後返回盡力而為的結果
        返回{
            “輸出”:輸出,
            「迭代」:self.max_iterations,
            「final_score」:批評.score,
            "note": "達到最大迭代次數",
        }


#用法
代理 = SelfRefiningAgent(max_iterations=3)
結果=代理.運行(
    “編寫一個驗證電子郵件地址的 Python 函數。”
    “處理邊緣情況。包括文件字串和類型提示。”
)
print(f"\n最終輸出(在 {result['iterations']} 次迭代之後):")
print(f"分數:{結果['final_score']}/10")
列印(結果[“輸出”])

6.3. Output Validation Pattern

除了使用LLM進行自我批評之外,我們還應該添加確定性驗證:

進口再
導入AST
從輸入 import Callable


類別輸出驗證器:
    """使用規則 + LLM 驗證代理輸出。"""

    def __init__(自身):
        self.rules: 列表[可調用] = []

    def add_rule(self, 名稱: str, check_fn: Callable[[str], bool],
                 錯誤訊息:str):
        self.rules.append({
            “姓名”:姓名,
            「檢查」:check_fn,
            “錯誤”:error_msg,
        })

    def validate(self, 輸出: str) -> 字典:
        錯誤=[]
        對於 self.rules 中的規則:
            如果不規則["check"](output):
                error.append(f"{rule['name']}: {rule['error']}")
        返回{
            「有效」:len(錯誤)== 0,
            「錯誤」:錯誤,
        }


# 例如:驗證程式碼輸出
驗證器 = OutputValidator()

驗證器.add_rule(
    “文法檢查”,
    lambda 代碼:_is_valid_python(代碼),
    “代碼有語法錯誤”,
)

驗證器.add_rule(
    “無硬編碼秘密”,
    lambda 程式碼:不是 re.search(
        r'(api_key|密碼|秘密)\s*=\s*["\'][^"\']+["\']', 代碼
    ),
    “包含硬編碼的秘密”,
)

驗證器.add_rule(
    “有_文檔字串”,
    lambda 代碼:代碼中的 '"""' 或代碼中的 "'''",
    “缺少文件字串”,
)


def _is_valid_python(代碼: str) -> bool:
    嘗試:
        ast.parse(代碼)
        回傳真
    除了語法錯誤:
        回傳錯誤


# 驗證
結果 = 驗證器.validate('''
def add(a: int, b: int) -> int:
    “”“加兩個數字。”“”
    返回 a + b
''')
print(結果) # {"valid": True, "errors": []}

提示:始終將基於LLM的批評(評估品質、邏輯)與確定性驗證(檢查語法、格式、規則)結合。 LLM 可以捕捉語義錯誤,規則可以捕捉結構錯誤——兩層保護比一層更好。


7. Human-in-the-Loop Patterns

7.1。為什麼我們需要人在環?

無論智能體多聰明,有些決定需要人類批准:

代理自治範圍:

  全自動監督人力驅動
  ◄──────────────────────┼── ────────────────────────►
  │ │ │
  “設定文字格式”“傳送電子郵件”“刪除資料庫”
  “總結文件”“部署到暫存”“轉移 10,000 美元”
  “運行測試”“創建公關”“解僱客戶”
  │ │ │
  無需批准 需要批准 始終以人為本
  執行決策前需要

7.2. Approval Workflow Pattern

從輸入導入 TypedDict, Literal
從 langgraph.graph 匯入 StateGraph,END
從 langgraph.checkpoint.memory 導入 MemorySaver
從 langchain_openai 導入 ChatOpenAI


類別 AgentState(TypedDict):
    任務:str
    計劃:str
    批准:布爾 |無
    結果:str
    需要批准:布爾


llm = ChatOpenAI(模型=“gpt-4o”,溫度=0)


def create_plan(狀態: AgentState) -> AgentState:
    """代理程式為任務建立計劃。"""
    響應 = llm.invoke(
        f“為以下內容建立詳細計劃:{state['task']}”
    )
    # 偵測任務是否需要批准
    high_risk_keywords = ["刪除","部署","發送","付款","生產"]
    需要批准=任何(
        state["task"].lower() 中的 kw for high_risk_keywords 中的 kw
    )
    返回{
        **狀態,
        「計劃」:回應.內容,
        「需要批准」:需要批准,
        「批准」:無,
    }


def check_approval(狀態: AgentState) -> str:
    """基於批准要求的路線。"""
    如果沒有說明[“requires_approval”]:
        return "execute" # 自動核准低風險任務
    若狀態[「已核准」]為「無」:
        return "wait_for_ human" # 需要人工輸入
    如果狀態[“已批准”]:
        返回“執行”
    返回“拒絕”


def wait_for_ human(狀態: AgentState) -> AgentState:
    “”“暫停並等待人工輸入。
    LangGraph中斷將在這裡暫停執行。
    ”“”
    # 在生產中,這會觸發通知
    # 圖表暫停直到人類做出反應
    返回狀態


defexecute_plan(狀態: AgentState) -> AgentState:
    """執行核准的計畫。"""
    響應 = llm.invoke(
        f“執行此計劃:\n{state['plan']}\n\n”
        f“任務:{狀態[‘任務’]}”
    )
    傳回{**狀態,「結果」:response.content}


defreject_plan(狀態: AgentState) -> AgentState:
    “”“人類拒絕了計劃。”“”
    return {**state, "result": "計畫被人工審核者拒絕。"}


# 使用檢查點建立圖表
檢查指針 = MemorySaver()

圖 = StateGraph(AgentState)
graph.add_node("create_plan", create_plan)
graph.add_node("wait_for_ human", wait_for_ human)
graph.add_node("執行",execute_plan)
graph.add_node(“拒絕”,reject_plan)

graph.set_entry_point("create_plan")
graph.add_conditional_edges("create_plan", check_approval, {
    “執行”:“執行”,
    "wait_for_Human": "wait_for_Human",
    “拒絕”:“拒絕”,
})
graph.add_conditional_edges("wait_for_ human", check_approval, {
    “執行”:“執行”,
    “拒絕”:“拒絕”,
    "wait_for_Human": "wait_for_Human",
})
graph.add_edge("執行", END)
graph.add_edge("拒絕", END)

應用程式 = graph.compile(checkpointer=checkpointer)

7.3. LangGraph Interrupt & Resume

LangGraph 支援中斷執行以等待人工輸入,然後恢復:

從 langgraph.graph 匯入 StateGraph,END
從 langgraph.checkpoint.memory 導入 MemorySaver
從 langgraph.types 導入中斷,命令


類別狀態(TypedDict):
    任務:str
    草稿:str
    回饋:str
    最終:str


defgenerate_draft(狀態:狀態)->狀態:
    """代理建立草稿。"""
    # ...產生草稿...
    return {**state, "draft": "此處草稿內容..."}


def human_review(狀態: 狀態) -> 狀態:
    “”“中斷以進行人工審查。”“”
    # 中斷()將在這裡暫停圖表
    反饋=中斷(
        # 顯示給人類的訊息
        {"draft": state["draft"], "message": "請審閱此草稿"}
    )
    返回{**狀態,「回饋」:回饋}


def revise(狀態: 狀態) -> 狀態:
    “”“根據反饋進行修改。”“”
    # ...根據回饋進行修改...
    return {**state, "final": f"修訂: {state['draft']} + {state['feedback']}"}


# 建構
檢查指針 = MemorySaver()

圖 = StateGraph(狀態)
graph.add_node(“生成”,generate_draft)
graph.add_node("評論", human_review)
graph.add_node("修訂", 修訂)

graph.set_entry_point("生成")
graph.add_edge("生成", "審查")
graph.add_edge("審閱", "修改")
graph.add_edge("修改", END)

應用程式 = graph.compile(checkpointer=checkpointer)

# 運行 — 將在 human_review 處暫停
config = {“可設定”:{“thread_id”:“review-1”}}
result = app.invoke({"task": "編寫 API 文件", "draft": "", "feedback": "", "final": ""}, config)

# ...人工審查並提供回饋...

# 透過人工回饋恢復
結果=應用程式.呼叫(
    Command(resume="看起來不錯,但添加更多範例"),
    配置,
)
列印(結果[“最終”])

7.4。人在環模式比較表

圖案何時使用複雜性使用者體驗
審核門高風險行為之前低簡單的是/否
回饋循環迭代內容創作平均審核→回饋→修改
Interrupt/ResumeComplex workflows with checkpointsCaoPause anywhere, resume later
升級代理人遇到不確定性低代理在困惑時詢問人類
協作人類+智能體協同工作曹即時共同編輯

提示: 在生產中,對於每個具有副作用的操作,從 批准門 開始。用戶對代理商更信任後,逐漸減少認可點數。這就是「漸進自治」模式。


8. 動手實作:用記憶+規劃+推理建構智能體

8.1。架構概覽

我們將建構一個具有完整記憶、規劃和推理能力的研究助理代理:

研究助理架構師:

  ┌────────────────────────────────────────────────────────┐
  │ 研究助理 │
  │ │
  │ ┌──────────────┐ ┐──────────────┐ ┌────────────┐ │
  │ │ 記憶 │ │ 規劃者 │ │ 推理者 │ │
  │ │ │ │ │ │ │ │
  │ │ 短期 │ │ 分解 │ │ CoT │ │
  │ │ 長期 │ │ 計畫執行 │ │ 自我檢測 │ │
  │ │ 情境式 │ │ 重新規劃 │ │ 反思 │ │
  │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
  │ │ │ │ │
  │ ┌──────▼────────────── ▼────────────────▼──────┐ │
  │ │ 狀態圖 (LangGraph) │ │
  │ │ │ │
  │ │ 計畫 → 研究 → 分析 → 寫作 → 回顧 │ │
  │ │ ▲ │ │ │
  │ │ └──────── 如果需要的話重新規劃 ──────────┘ │ │
  │ └────────────────────── ────────────────────────┘ │
  │ │
  │ 工具:網路搜尋、筆記記錄、文件編寫器 │
  └────────────────────────────────────────────────────────┘

8.2. Full Implementation

”“”
具有記憶+計劃+推理能力的研究助理代理。
需要: pip install langchain langchain-openai langgraph chromadb
”“”

從輸入導入 TypedDict,註釋
從日期時間匯入日期時間

從 langchain_openai 導入 ChatOpenAI、OpenAIEmbeddings
從 langchain_community.vectorstores 導入 Chroma
從 langchain_core.messages 導入 HumanMessage、SystemMessage
從 langgraph.graph 匯入 StateGraph,END
從 pydantic 匯入 BaseModel、Field


# --- 狀態 ---
類別研究狀態(TypedDict):
    查詢:str
    計劃:列表[str]
    目前步數:整數
    研究筆記:列表[str]
    草稿:str
    批評:str
    最終報告:str
    迭代:整數
    最大迭代次數:int
    記憶體上下文:str


# --- 記憶體模組 ---
類研究記憶:
    def __init__(self, persist_dir: str = "./research_memory"):
        self.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
        self.store = 色度(
            集合名稱=“研究史”,
            embedding_function = self.embeddings,
            persist_directory=persist_dir,
        )
        self.session_notes: 列表[str] = []

    def add_research(self, 主題: str, 結果: str):
        self.store.add_texts(
            texts=[f"主題:{主題}\n調查結果:{調查結果}"],
            元資料=[{
                「主題」:主題,
                「時間戳記」:datetime.now().isoformat(),
            }],
        )

    def recall(self, query: str, k: int = 3) -> str:
        docs = self.store.similarity_search(查詢, k=k)
        如果沒有文件:
            返回“未發現先前的研究。”
        返回“\n\n”.join(
            f“過去的研究:{doc.page_content}”,用於文件中的文檔
        )

    def add_session_note(self, note: str):
        self.session_notes.append(註釋)


記憶體=研究記憶體()


# --- 法學碩士設定 ---
planner_llm = ChatOpenAI(模型=“gpt-4o”,溫度=0)
Researcher_llm = ChatOpenAI(模型=“gpt-4o”,溫度=0.3)
writer_llm = ChatOpenAI(模型=“gpt-4o”,溫度=0.7)
ritic_llm = ChatOpenAI(模型=“gpt-4o”,溫度=0)


# --- 節點 ---
def load_memory(狀態: ResearchState) -> ResearchState:
    “”“加載相關的過去研究。”“”
    context = memory.recall(狀態[“查詢”])
    返回{**狀態,「記憶體上下文」:上下文}


def plan_research(狀態: 研究狀態) -> 研究狀態:
    """使用 CoT 建立研究計劃。"""
    回應 = planner_llm.invoke([
        系統訊息(內容=(
            “你是一名研究規劃者。一步步思考。\n”
            “[分析]需要研究哪些方面?\n”
            “[計劃] 創建 4-6 個具體研究步驟。\n”
            “僅返回編號的步驟。”
        )),
        人類留言(內容=(
            f“研究查詢:{state['query']}\n”
            f“過去的上下文:{state['memory_context']}”
        )),
    ])
    步驟= [
        line.strip().lstrip("0123456789.)-").strip()
        對於response.content.strip().split("\n")中的行
        if line.strip() 和 any(c.isalpha() for c in line)
    ]
    返回{**狀態,“計劃”:步驟,“current_step”:0,“research_notes”:[]}


def Research_step(狀態: ResearchState) -> ResearchState:
    “”“執行目前的研究步驟。”“”
    如果狀態[“current_step”] >= len(狀態[“計劃”]):
        返回狀態

    步驟=狀態[“計劃”][狀態[“目前步驟”]]
    prev_notes = "\n".join(state["research_notes"][-3:])
    回應 = Researcher_llm.invoke([
        系統訊息(內容=(
            “你是一位徹底的研究人員。對於這一步:\n”
            "1.深入研究主題\n"
            "2.提供具體的事實、數據、範例\n"
            “3. 盡可能引用來源\n”
            “全面但重點突出。”
        )),
        人類留言(內容=(
            f"總體查詢:{state['query']}\n"
            f"當前步驟:{步驟}\n"
            f“之前的發現:\n{prev_notes}”
        )),
    ])

    筆記=狀態[“研究筆記”] + [
        f"[步驟 {state['current_step'] + 1}] {step}\n{response.content}"
    ]
    memory.add_session_note(f"已研究:{step}")

    返回{
        **狀態,
        「research_notes」:筆記,
        「當前步」:狀態[「當前步」] + 1,
    }


def check_research_done(狀態: ResearchState) -> str:
    “”“檢查是否還有更多的研究步驟。”“”
    如果狀態[“當前步”] < len(state["plan"]):
        return "continue_research"
    return "write_report"


def write_report(state: ResearchState) -> 研究狀態:
    “”“根據研究筆記撰寫報告。”“”
    all_notes = "\n\n".join(state["research_notes"])
    回應 = writer_llm.invoke([
        系統訊息(內容=(
            “你是一位專家報告撰寫者。寫出結構良好的報告”
            “基於研究筆記的報告。包括:\n”
            “- 執行摘要\n”
            “- 主要發現及詳細資訊\n”
            "- 分析與見解\n"
            “- 結論與建議”
        )),
        人類留言(內容=(
            f"查詢:{state['query']}\n\n研究筆記:\n{all_notes}"
        )),
    ])
    傳回{**狀態,「草稿」:response.content}


def critique_report(state: ResearchState) -> ResearchState:
    “”“對報告進行自我批評。”“”
    響應=critic_llm.invoke([
        系統訊息(內容=(
            “你是一位嚴格的編輯。批評這份報告:\n”
            “1. 資訊是否準確且有充分依據?\n”
            "2.邏輯結構是否?\n"
            “3. 是否存在差距或缺失的觀點?\n”
            "4. 得分 1-10。如果得分 >= 8,請說「已批准」。\n"
            “否則列出需要的具體改進。”
        )),
        人類留言(內容=(
            f"查詢:{state['query']}\n\n報告:\n{state['draft']}"
        )),
    ])
    返回{
        **狀態,
        「批評」:回應.內容,
        「迭代」:狀態[“迭代”] + 1,
    }


def check_quality(狀態: ResearchState) -> str:
    “”“基於批評的路線。”“”
    如果狀態[“critique”].upper()中“批准”:
        返回“最終確定”
    如果狀態[“迭代”] >= 狀態[“最大迭代”]:
        返回“最終確定”
    返回“修改”


def revise_report(state: ResearchState) -> ResearchState:
    “”“基於批評(自我反思)進行修改。”“”
    回應 = writer_llm.invoke([
        系統訊息(內容=(
            “根據批評修改報告。”
            “解決提到的每個問題。”
            “保持相同的結構,但提高品質。”
        )),
        人類留言(內容=(
            f"原始報告:\n{state['draft']}\n\n"
            f"批評:\n{狀態['批評']}"
        )),
    ])
    傳回{**狀態,「草稿」:response.content}


def Finalize(狀態: ResearchState) -> ResearchState:
    """完成並儲存到記憶體中。"""
    # 保存到長期記憶
    記憶體.add_research(
        主題=狀態[“查詢”],
        調查結果=狀態[“草稿”][:500],
    )
    返回 {**state, "final_report": state["draft"]}


# --- 建立圖表 ---
圖 = StateGraph(ResearchState)

graph.add_node("load_memory", load_memory)
graph.add_node("計畫", plan_research)
graph.add_node(“研究”,research_step)
graph.add_node("寫", write_report)
graph.add_node("批評", critique_report)
graph.add_node("修訂", revise_report)
graph.add_node("最終確定", 最終確定)

graph.set_entry_point(“載入記憶體”)
graph.add_edge("load_memory", "計畫")
graph.add_edge("計畫", "研究")
graph.add_conditional_edges("研究", check_research_done, {
    "continue_research": "研究",
    "write_report": "寫",
})
graph.add_edge("寫", "批評")
graph.add_conditional_edges("批評", check_quality, {
    “修改”:“修改”,
    “最終確定”:“最終確定”,
})
graph.add_edge("revise", "critique") # 修改後重新批評
graph.add_edge("最終確定", END)

應用程式 = graph.compile()


# --- 運行 ---
def 研究(查詢:str)-> str:
    結果 = app.invoke({
        「查詢」:查詢,
        「計劃」:[],
        「目前步數」:0,
        「研究筆記」:[],
        “草稿”:“”,
        “批評”:“”,
        “最終報告”:“”,
        「迭代」:0,
        「最大迭代次數」:2,
        “記憶體上下文”:“”,
    })
    print(f"已在 {result['iteration']} 修訂版中完成")
    回傳結果[“最終報告”]


#用法
報告=研究(「2025年企業AI代理趨勢分析」)
列印(報告)

8.3。詳細流程圖

完整的代理商流程:

  使用者查詢
      │
      ▼
  ┌────────────┐
  │ 載入記憶體 │ ← 回顧過去的研究
  └──────┬────────┘
         │
  ┌──────▼────────┐
  │ 計畫 (CoT) │ ← 分解查詢 → 4-6 步驟
  └──────┬────────┘
         │
  ┌──────▼────────┐
  │ 研究 │◄──┐
  │ 步驟N │ 循環直到所有
  └──────┬────────┘ │ 步驟完成
         │────────────┘
         │
  ┌──────▼────────┐
  │ 撰寫報告 │ ← 綜合所有研究
  └──────┬────────┘
         │
  ┌──────▼────────┐
  │ 自我批評│ ← 評分+發現問題
  └──────┬────────┘
         │
     ┌───┴───┐
     │分數≥8? │
     └───┬───┘
    否 │ 是
    │ └──────►┌──────────┐
    │ │ 完成 │ ← 儲存到內存
    ▼ └──────────┘
  ┌──────────┐
  │ 修改 │ ← 修復問題
  └────┬──────┘
       │
       └──► 回傳批評(最多 2 次迭代)

提示:此模式可以擴展:在研究步驟中添加網絡搜索工具,在最終確定之前添加人工審查,添加情景記憶以記住哪種研究方法是有效的。模組化架構使得迭代變得容易。


9. 總結

本文涵蓋了將模型轉變為真實代理的三個最重要的支柱:

能力關鍵概念工具/技術
記憶體短期、長期、情境、語意、工作LangChain記憶體、向量儲存、Redis、自訂管理器
規劃任務分解、規劃與執行、分層結構化輸出,LangGraph 狀態機
推理CoT,思想樹,自洽CoT 提示、多路徑生成、投票
自我反省反思、自我批評、驗證批判循環、輸出驗證器、迭代細化
人在環批准、回饋、中斷/恢復LangGraph 檢查點、中斷模式

需要記住的重點:

  1. 記憶體不是奢侈品-它是每個製作代理的要求
  2. 執行前規劃-永遠分解複雜的任務
  3. 推理痕跡有助於調試和改進代理行為
  4. 自我反思是智能體如何在無需重新訓練的情況下自我改進
  5. 人機互動是高風險行動所必需的安全網
  6. 結合所有 — 最強大的代理是結合了所有 5 種功能的代理

10.下一篇文章

在第 16 課:代理評估與測試中,我們將學習如何系統地評估和測試 AI 代理:

  • 代理評量指標:任務完成狀況、準確性、效率
  • 基準套件以及如何建立測試案例
  • 針對代理程式配置的 A/B 測試
  • 更新提示/模型時進行迴歸測試
  • 生產監控 — 追蹤代理在現實世界中的行為

一旦智能體具備了記憶、計劃和推理能力,下一個問題就是:「我們如何知道智能體運作良好?」 第 16 課將回答這個問題。