大数跨境

LangChain 实战第12课:业务很复杂,如何让AI真的“懂”业务,自动思考并多次调用“工具”?

LangChain 实战第12课:业务很复杂,如何让AI真的“懂”业务,自动思考并多次调用“工具”? 玩AI的方可乐
2025-09-29
1
导读:手把手教学,10 分钟见结果

 

你好,我是方可乐。
一个正在深耕AI编程的30+的AI应用开发工程师。
用AI编程开发过Web应用网站,浏览器插件,

微信小程序,AI智能体,RAG系统。

注公众号&添加微信:ThinkFun666

领取【AI编程资料包】



 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

去年6月份,我做了一个连自己都觉得疯狂的决定:裸辞,All in AI。

现在已经换赛道成功,继续在工作中探索。


 

 

今天我们来讲React,ReAct = Reasoning + Acting(推理 + 行动)。
为什么我们需要React呢?先来回顾上节课的坑。

在上一课里,我们用 Tools Agent 让 AI 可以调用工具,比如生成密码、做 Base64 编解码。

但 Tools Agent 有个明显限制:只能调用一次工具,或者我们提前写死调用顺序

一旦任务需要多步,比如“生成密码再编码”,AI 就没法自己完成。

ReAct 就能够很好地解决这个问题。
它的特点是:

  • • AI 会先思考(我要解决什么问题?需要用哪个工具?)
  • • 再行动(调用某个工具)
  • • 再思考(结果够了吗?还要不要继续?)
  • • 最终给出答案

最大的区别在于:

  • • Tools Agent:只会调用一次工具
  • • ReAct Agent:可以调用多次工具,直到完成目标

LangChain 如何实现 ReAct?

在 LangChain 里,用 AgentExecutor 加上 AgentType.ZERO_SHOT_REACT_DESCRIPTION 就能启用 ReAct。

核心就是它的 prompt 模板,分三部分:
prefix:开场白,告诉 AI 它是一个会思考和调用工具的助手。
你是一个会思考和行动的助手,可以灵活选择工具来帮用户解决问题。
suffix:结尾模板,必须包含两个占位符:

  • • {input} —— 用户输入
  • • {agent_scratchpad} —— AI 的“草稿本”,记录思考/行动/观察过程

        例如:
        开始思考!记住要使用中文回答。  问题: {input}思考: {agent_scratchpad}

format_instructions:格式说明,LangChain 自动生成(不用手写)。
!!!注意

  • • {input} 和 {agent_scratchpad} 是固定的,不能删。

老规矩,下面我们上代码,当你看完完整的代码和效果之后,就知道是怎么回事了。
新建文件12_react_call_tools.py


            
            
            
            
             
            
            
            
            import os
import
 random
import
 base64
from
 dotenv import load_dotenv

from
 langchain_openai import ChatOpenAI
from
 langchain.agents import initialize_agent, AgentType
from
 langchain.tools import tool

load_dotenv()

# 初始化 LLM

llm = ChatOpenAI(
    model="deepseek-chat",
    base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1"),
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    temperature=0
)

# 工具1:密码生成器(沿用11课)

@tool

def
 generate_password(level: str) -> str:
    """根据复杂度生成密码,复杂度可选:low / medium / high"""

    chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    special = "!@#$%^&*()_+-=[]{}|;:,.<>?"
    length = {"low": 6, "medium": 10, "high": 16}.get(level, 8)
    pool = chars + special if level == "high" else chars
    return
 "".join(random.choice(pool) for _ in range(length))

# 工具2:Base64 编码(沿用11课)

@tool

def
 base64_encode(text: str) -> str:
    """将输入字符串进行 Base64 编码"""

    return
 base64.b64encode(text.encode()).decode()

# 工具3:Base64 解码(沿用11课)

@tool

def
 base64_decode(text: str) -> str:
    """将 Base64 字符串解码为原始字符串"""

    return
 base64.b64decode(text.encode()).decode()

tools = [generate_password, base64_encode, base64_decode]

# 使用 initialize_agent 创建 ReAct Agent

agent_executor = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    handle_parsing_errors=True,
    agent_kwargs={
        "prefix"
: """You are a helpful assistant that can use tools to solve problems. Always respond in Chinese.

Use the following format strictly:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take (generate_password, base64_encode, or base64_decode)
Action Input: the input to the action
Observation: the result of the action
... 
(this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question in Chinese

IMPORTANT: Always end with "Final Answer:" followed by your response. Never add extra text after giving the final answer."""
,
        "suffix"
: "Begin!\n\nQuestion: {input}\nThought: {agent_scratchpad}"
    }
)

print
("=== ReAct 密码助手(思考 + 行动)===\n")

while
 True:
    user_input = input("你:")
    if
 user_input.lower() in ["quit", "exit", "退出"]:
        print
("退出。")
        break

    result = agent_executor.invoke({"input": user_input})
    print
("AI:", result["output"], "\n")

正常运行后,结果如下:

这里有个挺坑的地方,就是提示词里面的格式得写对,不然就会导致格式错误一直在思考循环。

ReAct提示词结构分析

固定的核心结构(不能改)


            
            
            
            
             
            
            
            
            "prefix": """[角色定义] + [格式规范]""","suffix": "Begin!\n\nQuestion: {input}\nThought: {agent_scratchpad}"

suffix部分是固定的,包含:

  • • {input} - 用户输入的占位符
  • • {agent_scratchpad} - Agent思考过程的占位符
  • • Begin! 和 Question: 是ReAct框架的标准开始格式

可以修改的部分

A. 角色定义部分(完全可自定义)


            
            
            
            
             
            
            
            
            "You are a helpful assistant that can use tools to solve problems. Always respond in Chinese."

可以改为:

  • • "You are a professional data analyst..."
  • • "You are a coding expert..."
  • • "You are a customer service representative..."

B. 工具名称列表(必须与实际工具匹配)


            
            
            
            
             
            
            
            
            "Action: the action to take (generate_password, base64_encode, or base64_decode)"

这里的工具名称必须与你定义的工具函数名完全一致。

C. 语言要求(可选)


            
            
            
            
             
            
            
            
            "Always respond in Chinese""Final Answer: the final answer to the original input question in Chinese"

 



 


 

 

 

 

 

 

 

 

 

对AI应用开发感兴趣的同学,欢迎加微信申请入群交流学习。

想要学习AI应用开发的同学,可以参照我的代码跑起来,举一反三,一天一个脚印的进步,我相信,会足够坚实。


接下来100天,我会记录从Java程序员到AI应用开发工程师的完整转型路:每一个困惑、每一次突破、每一个真实瞬间。

当前是30/100。

如果你也想了解AI应用开发到底是什么,如果你也在考虑转型但还在犹豫,那就跟着我的记录,一起探索。


继续折腾中,有问题随时交流 🤝
微信号:ThinkFun666



我的免费AI编程交流群,欢迎加入讨论AI编程玩法(加我微信,说明需求和来意,申请入群)



 

 



推荐阅读:

我就喜欢干这种傻事!为什么转型AI应用开发,我不建议你直接从看书开始学起?

猛然醒悟:原来 AI 编程这件事情,是有门槛的,90%的新手卡在这些地方

30岁转行 AI 应用开发:多久能学会?答案出乎意料

30岁,我放弃写了7年的Java,成功转型AI应用开发

30岁,转型AI应用开发,需要会什么技术?

30岁,空窗期一年,靠什么成功转型AI应用开发?

30岁,没报课,如何从0自学转型AI应用开发?

【声明】内容源于网络
0
0
玩AI的方可乐
1234
内容 502
粉丝 0
玩AI的方可乐 1234
总阅读204
粉丝0
内容502