AI Agents in LangGraph-1

从零手写了一个 ReAct范式的 Agent

  • [从零手写了一个 ReAct范式的 Agent](#从零手写了一个 ReAct范式的 Agent)
    • [核心机制:ReAct 循环工作流](#核心机制:ReAct 循环工作流)
    • [1. 基础准备与客户端测试](#1. 基础准备与客户端测试)
    • [2. 核心类定义:带有记忆的 Agent 封装](#2. 核心类定义:带有记忆的 Agent 封装)
    • [3. Prompt 引导与工具定义(Agent 的"大脑"与"双手")](#3. Prompt 引导与工具定义(Agent 的“大脑”与“双手”))
      • [脑部指令(System Prompt)](#脑部指令(System Prompt))
      • 手头的工具
    • [4. 正则解析与自治循环引擎](#4. 正则解析与自治循环引擎)
    • 使用示例

ReAct:(Reasoning + Acting,推理与行动)

从零手写了一个 ReAct范式的 Agent

本文以最简单的逻辑代码为基础,用浅显易懂的语言,描述ReAct范式是啥

核心机制:ReAct 循环工作流

agent遵循的一般范式:

bash 复制代码
用户提问 -> [Thought 思考] -> [Action 发起工具调用] -> [PAUSE 暂停并等待]
                                                              │
回答用户 <- [Answer 输出] <- [Observation 喂回结果] <- [执行 Python 函数]

1. 基础准备与客户端测试

python 复制代码
from langchain_openai import ChatOpenAI
import os
from load_dotenv import load_dotenv
load_dotenv()

if os.environ.get("OPENAI_API_KEY"):
    print("Bro API KEY Variable exists")
else :
    raise ValueError("OPENAI_API_KEY not found")

from langchain_core.prompts import PromptTemplate
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser, PydanticOutputParser


llm_openai = ChatOpenAI(model = "gpt-5-mini-2025-08-07", temperature=0)

代码作用:加载环境变量(读取 .env 中的 OPENAI_API_KEY),初始化 OpenAI SDK 客户端。

2. 核心类定义:带有记忆的 Agent 封装

python 复制代码
class Agent:
    def __init__(self, system=""):
        self.system = system
        self.messages = []
        if self.system:
            self.messages.append({"role": "system", "content":system})

    def __call__(self, message):
        self.messages.append({"role": "user", "content": message})
        result = self.execute()
        self.messages.append({"role": "assistant", "content": result})
        return result

    def execute(self):
        completion = llm_openai.invoke(self.messages)
        return completion.content

设计巧思:

  • 对话上下文维护(self.messages):大模型本身是没有记忆模块,Agent 类通过一个list维护了从 system prompt 到每一次 user 和 assistant 的完整对话历史。

  • 可调用对象(call ):重写了 call 方法,使得实例可以像函数一样被直接调用(例如 abot("你好"))。每次调用都会把输入追加到对话历史中,向 OpenAI 发送请求,并记录大模型的返回内容。

  • 确定性输出(temperature=0):在上一节中将温度设为 0,确保大模型的推理和工具选择高度稳定、可预测。

3. Prompt 引导与工具定义(Agent 的"大脑"与"双手")

脑部指令(System Prompt)

python 复制代码
prompt = """
You run in a loop of Thought, Action, PAUSE, Observation.
At the end of the loop you output an Answer
Use Thought to describe your thoughts about the question you have been asked.
Use Action to run one of the actions available to you - then return PAUSE.
Observation will be the result of running those actions.

Your available actions are:

calculate:
e.g. calculate: 4 * 7 / 3
Runs a calculation and returns the number - uses Python so be sure to use floating point syntax if necessary

average_dog_weight:
e.g. average_dog_weight: Collie
returns average weight of a dog when given the breed

Example session:

Question: How much does a Bulldog weigh?
Thought: I should look the dogs weight using average_dog_weight
Action: average_dog_weight: Bulldog
PAUSE

You will be called again with this:

Observation: A Bulldog weights 51 lbs

You then output:

Answer: A bulldog weights 51 lbs
""".strip()

prompt 变量定义了 ReAct 的少样本规则(Few-Shot Few-Examples),告诉大模型必须严格按照 Thought -> Action -> PAUSE 的格式输出,并在观察完成后输出 Answer。

手头的工具

python 复制代码
def calculate(what):
    return eval(what)

def average_dog_weight(name):
    if name in "Scottish Terrier": 
        return("Scottish Terriers average 20 lbs")
    elif name in "Border Collie":
        return("a Border Collies average weight is 37 lbs")
    elif name in "Toy Poodle":
        return("a toy poodles average weight is 7 lbs")
    else:
        return("An average dog weights 50 lbs")

known_actions = {
    "calculate": calculate,
    "average_dog_weight": average_dog_weight
}
  • calculate:利用 Python 的 eval() 实时计算数学表达式。
  • average_dog_weight:模拟一个查询数据库或 API 的函数,返回犬种体重。
  • known_actions(工具注册表):这是一个字典,建立了文本名称(如 "calculate")到实际 Python 函数对象(如 calculate)的映射关系。

4. 正则解析与自治循环引擎

python 复制代码
action_re = re.compile('^Action: (\w+): (.*)$')   # python regular expression to selection action
def query(question, max_turns=5):
    i = 0
    bot = Agent(prompt)
    next_prompt = question
    while i < max_turns:
        i += 1
        result = bot(next_prompt)
        print(result)
        actions = [
            action_re.match(a) 
            for a in result.split('\n') 
            if action_re.match(a)
        ]
        if actions:
            # There is an action to run
            action, action_input = actions[0].groups()
            if action not in known_actions:
                raise Exception("Unknown action: {}: {}".format(action, action_input))
            print(" -- running {} {}".format(action, action_input))
            observation = known_actions[action](action_input)
            print("Observation:", observation)
            next_prompt = "Observation: {}".format(observation)
        else:
            return

核心作用 :Agent 的"动力引擎(Execution Engine)",实现真正的自动化。

原理解析:

  • 正则提取(action_re):从大模型返回的文本中,精准提取出 Action: 工具名: 参数(例如从 Action: calculate: 37 + 20 中提取出 calculate 和 37 + 20)。
  • 死循环/最大轮次防护(max_turns=5):防止 Agent 进入死循环或无限消耗 Token,设置熔断保护。
  • 控制流反转:执行 Python 函数得到结果(observation),包装成 Observation: xxx 的格式追加回 Prompt,驱动 Agent 进行下一轮思考。

使用示例

调用 query("I have 2 dogs, a border collie and a scottish terrier. What is their combined weight"),底层发生多轮的交互互动:

shell 复制代码
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                        用户提出复杂问题                                                    │   
│ "I have 2 dogs, a border collie and a scottish terrier.  What is their combined weigh?" │
└─────────────────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
  【第 1 轮 Loop】
  • LLM 思考:需要先查 Border Collie 体重。
  • LLM 输出:
    Thought: I should look up the weight of a Border Collie.
    Action: average_dog_weight: Border Collie
    PAUSE
  • Python 引擎拦截:匹配到 Action,暂停调用 LLM!
  • 执行 Python 函数:average_dog_weight("Border Collie") -> "37 lbs"
  • 反馈观察结果:Observation: a Border Collies average weight is 37 lbs
                                    │
                                    ▼
  【第 2 轮 Loop】
  • LLM 思考:已知边牧 37lbs,还需要查 Scottish Terrier 体重。
  • LLM 输出:
    Thought: Now I need to look up the weight of a Scottish Terrier.
    Action: average_dog_weight: Scottish Terrier
    PAUSE
  • Python 引擎拦截:执行 average_dog_weight("Scottish Terrier") -> "20 lbs"
  • 反馈观察结果:Observation: Scottish Terriers average 20 lbs
                                    │
                                    ▼
  【第 3 轮 Loop】
  • LLM 思考:两只狗体重已知(37 和 20),需要计算 37 + 20。
  • LLM 输出:
    Thought: I need to calculate 37 + 20.
    Action: calculate: 37 + 20
    PAUSE
  • Python 引擎拦截:执行 calculate("37 + 20") -> 57
  • 反馈观察结果:Observation: 57
                                    │
                                    ▼
  【第 4 轮 Loop】
  • LLM 思考:所有信息收集完毕,计算完成,可以给出最终答案了。
  • LLM 输出(不含 Action):
    Answer: The combined weight of a Border Collie and a Scottish Terrier is 57 lbs.
  • Python 引擎检测:没有匹配到 Action,退出 while 循环,任务完成!
相关推荐
Csvn4 小时前
第 28 章 案例四 多智能体协作系统
人工智能·aigc·agent
IT_陈寒4 小时前
Java中equals方法比了个寂寞?原来这才是正确的重写姿势
前端·人工智能·后端
吴佳浩4 小时前
Agent 怎么做自动化评测?构建端到端的 Agent Evaluation 体系
人工智能·agent·ai编程
火山引擎开发者社区4 小时前
火山引擎云数据库 TiDB 版公测开启,MySQL 架构升级的一站式选择
人工智能
代码方舟4 小时前
Java数据工程:利用天远全网运营商三要素优化线上实名认证合规体验
java·人工智能
Csvn4 小时前
第 27 章 案例三 自动化工作流 Agent
人工智能·aigc·agent
知几蜗牛4 小时前
AI眼镜把记忆放上云,怎样证明云端也看不见?
人工智能
知几蜗牛4 小时前
训练数据越多越好吗?用LeRobot讲清数据质量与版本化
人工智能
知几蜗牛4 小时前
PR合并慢,别再只看平均时长:GitHub把等待拆成了三段
人工智能
知几蜗牛4 小时前
AI账单失控前,团队真正缺的不是更便宜的模型
人工智能