Agent工具调用范式:ReAct 和Function Calling

Agent工具调用范式

最近看到qwen3.5发布了,但是对于Function Calling 没有找到适配好的模型,所以用ReAct模式来试用一下。之前基于qwen3做了Function Calling模式的agent。刚好有机会把两种主流的工具调用范式都落地了一遍,索性整理记录一下我踩过的坑,以及两种范式的真实差异,给大家做个参考。


项目前置:先搭好我们的知识库

做客服 Agent,首先得有业务知识库,用来做售后政策的检索,我写了一个简单的ingest.py脚本,把我们的售后政策转成了 FAISS 向量库:

ini 复制代码
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_ollama import OllamaEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document

# 版售后政策
raw_text = """
《智能助手售后政策 2026版》
1. 退款规则:未发货订单可随时申请全额退款。
2. 已发货规则:已发货订单需在签收后 7 天内,保持包装完好,联系客服申请退货。
3. 快递费用:非质量问题退货,由买家承担运费。
4. 特殊商品:定制化订单不支持 7 天无理由退换。
"""
documents = [Document(page_content=raw_text)]

# 用递归切分器做文本切片,保证语义不被拆断
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
chunks = text_splitter.split_documents(documents)

# 用本地的nomic-embed-text做嵌入,生成向量库
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vector_db = FAISS.from_documents(documents=chunks, embedding=embeddings)
vector_db.save_local("faiss_index")

跑通这个脚本,我们就有了本地的向量知识库,接下来就是做两个不同版本的 Agent 了。

第一个版本:原生结构化的 LangGraph Agent

Qwen3做的一个基于 LangGraph 的 Function Calling 版本。

这个版本的核心是依赖模型原生的 Function Calling 能力,用 LangGraph 的状态机来管理多轮交互,工具调用都是标准化的结构化数据,不用自己处理文本解析。

核心实现

ini 复制代码
# 对比ReAct的长Prompt,这个System Prompt真的太简洁了,不用约束格式
system_prompt = """你是专业的企业客服。严禁捏造不存在的信息,必须基于工具返回的信息。
排版要求:
1. 严禁使用 `#` 等大号 Markdown 标题语法。
2. 多个订单请直接使用无序列表 `-` 排版,并在订单号上加粗。"""

# 一行代码创建Agent,LangGraph帮你做好了所有的事情
agent = create_react_agent(
    model=llm,  # 前提是模型要支持Function Calling
    tools=[get_order_status, search_policy],
    prompt=system_prompt,
    checkpointer=memory,  # 内置的状态持久化,自动帮你管理会话历史
)

上下文管理,ReAct 还要自己拼接chat_history字符串,LangGraph 只要传一个thread_id,它自动帮你把历史记录存起来,每次只需要传最新的用户消息就行,完全不用管历史的事情,开发效率高了太多。


第二个版本:纯文本驱动的 ReAct Agent

ReAct 的核心逻辑其实很简单:用 Prompt 约束模型,让它用自然语言模拟「思考 - 行动 - 观察」的循环,所有的交互都是纯文本,不依赖模型的原生能力。

核心实现

ini 复制代码
# 最关键的就是这个硬编码的Prompt,强制约束模型的输出格式
REACT_PROMPT_TEMPLATE = """你是专业的企业客服。严禁捏造不存在的信息,必须基于工具返回的信息进行回答。
要使用工具,你必须且只能使用以下严格的格式:
Thought: 我需要使用工具吗? Yes
Action: 需要执行的工具名称,必须是 [{tool_names}] 中的一个
Action Input: 传给工具的输入参数
Observation: 工具返回的执行结果

当你已经收集到足够的信息来回答用户,或者你不需要使用任何工具时,你必须且只能使用以下格式输出最终答案:
Thought: 我需要使用工具吗? No
Final Answer: [在这里写下你给用户的最终回复,必须使用中文]

现在开始!

历史对话记录:
{chat_history}

用户的新输入: {input}
{agent_scratchpad}
"""

但是落地的时候,我踩了不少坑,比如 Qwen3.5 的<think>推理块,ReAct 的解析器根本看不懂,导致每次都解析失败,最后我加了一个小的处理函数,在 LLM 输出到解析器之前,把 think 块剥离了:

python 复制代码
def _strip_think(msg: AIMessage) -> AIMessage:
    cleaned = re.sub(r"<think>.*?</think>", "", msg.content, flags=re.DOTALL).strip()
    # 防止返回空消息
    if not cleaned:
        cleaned = "..."
    return AIMessage(
        content=cleaned,
        additional_kwargs=msg.additional_kwargs,
        id=msg.id,
    )
llm_for_agent = llm | RunnableLambda(_strip_think)

还有流式输出的问题,ReAct 的中间思考过程是给模型自己看的,不能给用户,所以我又加了一个滑动窗口缓冲,检测到Final Answer:标记之后,才把后面的内容推给前端,过滤掉中间的思考过程。


两种范式的核心差异

做完两个版本之后,我整理了一下它们的核心差异,大概是这样的:

对比维度 ReAct 范式 Graph/Function Calling 范式
模型依赖 全模型通用,无原生能力要求,小模型也能跑 模型专属,必须支持原生 Function Calling
格式约束 纯文本 Prompt 驱动,自定义格式,全靠约束 原生结构化输出,标准字段,开箱即用
执行流程 文本解析循环,靠 AgentExecutor 解析文本 状态机循环,LangGraph 管理状态
上下文管理 手动拼接字符串,轻量但易错乱 role的 messages 数组,自动持久化
工程复杂度 高,要自己处理各种兼容、过滤 低,框架已经做好了所有兼容

踩坑:那些我踩过的坑

ReAct 版本的坑

  1. Prompt 的鲁棒性真的是生命线 :一开始直接用FC模式,模型有时候会输出中文的「思考:」而不是Thought:,导致解析器直接报错,最后只能用强约束的 Prompt,再加解析错误兜底。
  2. Action Input 的格式兼容:LLM 有时候会把输入写成 JSON 对象,而不是纯字符串,导致工具解析失败,最后我在工具里加了一个 JSON 解包的逻辑,自动处理这种情况。
  3. max_iterations 要调大:因为解析失败会消耗迭代次数,一开始设的 5,很容易就耗尽了,最后调到 10,给容错留了空间。

Function Calling 版本的坑

  1. 模型必须支持 Function Calling:一开始我用Qwen3.5 模型,不支持 FC,输出的完全和预想的不一样,模型会输出..+json,导致LangGraph完全没法运作。中间看了很多都没有找到比较好的,最后换成了 Qwen3 的才行。
相关推荐
谁在黄金彼岸2 小时前
构建一个多Agent系统(Multi-Agent System, MAS)方法论
人工智能
jinanwuhuaguo2 小时前
OpenClaw字节跳动的三只不同的claw龙虾飞书妙搭 OpenClaw、ArkClaw、扣子 OpenClaw 核心区别深度解析
人工智能·语言模型·自然语言处理·visual studio code·openclaw
咚咚王者2 小时前
人工智能之语言领域 自然语言处理 第十八章 Python NLP生态
人工智能·python·自然语言处理
yeflx2 小时前
三维空间坐标转换早期笔记
人工智能·算法·机器学习
zzh940772 小时前
Gemini 3.1 Pro 2026年国内使用指南:技术解析与镜像站实测
人工智能
初学大模型2 小时前
基于三层架构的自动驾驶系统设计:环境建模、标准驾驶与风险调制
人工智能
●VON2 小时前
半小时从零开发鸿蒙记事本应用:AI辅助开发实战
人工智能·华为·harmonyos
特立独行的猫a2 小时前
ESP32小智AI的WebSocket 调试工具实现,小智AI后台交互过程揭秘(一、开篇介绍 )
人工智能·websocket·网络协议·esp32·小智ai
qq_397562312 小时前
卷积神经网络 CNN
人工智能·神经网络·cnn