从单步执行到多步决策与状态流转

最近不知道大家有没有关注一些招聘平台的招聘信息,其实看这些平台我相信最多的关键词就Cot、ReAct等,今天咱们主要讲ReAct(Reasoning + Acting),这种范式的提出主要目的是解决纯推理模型易产生“幻觉”和纯行动模型缺乏高层规划的局限性。 这个说法有点抽象,我想换一种说法,这种方式其实是改变智能体的行为方式,咱们前面写到东西其实是一种单步智能体,他的执行过程是这样的:

用户问题 → 选一个工具 → 执行 → 返回结果

这种方式其实有一点不好,就是智能体判断完可能是什么任务后直接就开始执行,得到结果就给了用户,这种方式得到的结果质量可能一般,所以为了提升智能体执行任务返回结果的质量,姚顺雨在2020年提出的了这种AI范式,其核心在于让大语言模型通过“推理-行动-观察”的循环与外部环境交互,以完成复杂任务。‌可以这样表示:

用户问题 → 思考 → 调工具 → 看结果 → 再思考 → 再决定下一步 → 最终回答

最小循环Agent

今天我们要做的这样一件事,让我们前面写的智能体:

  1. 先判断用什么工具;
  2. 调一次工具
  3. 拿到结果后在做一次总结
  4. 返回最终答案

也就是实现 状态+节点+流转

Question → Tool Choice → Tool Output → Final Answer

代码实现

咱们需要修改咱们前面写的agent.py文件。

工具选择planner

首先对咱们的的工具选择进行一定的改造,前面咱们的工具选择是从已定义的工具中选择合适的工具回答问题,这次咱们再补充一点,如果没有合适的工具那么使用大语言模型回答问题:

def choose_tool(query, tools):
    tool_desc = "\n".join([
        f"{t['name']}: {t['description']}" for t in tools
    ])

    prompt = f"""
                You are an AI agent.
                
                Available tools:
                {tool_desc}
                
                User question:
                {query}
                
                Return JSON:
                {{"tool": "...", "input": "..."}}
              """

    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[{"role": "user", "content": prompt}]
    )

    content = response.choices[0].message.content

    try:
        return json.loads(content)
    except:
        return {"tool": "llm", "input": query}

执行工具executor

定义执行工具函数,该函数将会上一步选择工具执行,同时返回响应的中间执行结果:

def execute_tool(decision, tools, rag=None):
    tool_name = decision["tool"]
    tool_input = decision["input"]

    for t in tools:
        if t["name"] == tool_name:
            if tool_name == "rag":
                result = t["func"](tool_input, rag)
            else:
                result = t["func"](tool_input)

            return {
                "tool_name": tool_name,
                "tool_input": tool_input,
                "tool_output": result
            }

    return {
        "tool_name": "none",
        "tool_input": tool_input,
        "tool_output": "No valid tool found."
    }

执行输出responder

咱们前面已经选择的工具,并且得到了中间的执行结果,随后智能体将会观察执行结果,在执行结果的基础上再进行一步思考得出最终执行结果:

def generate_final_answer(query, tool_result):
    prompt = f"""
                You are an AI assistant
                
                The user asked:
                {query}
                
                A tool was used:
                Tool name: {tool_result['tool_name']}
                Tool input: {tool_result['tool_input']}
                Tool output: {tool_result['tool_output']}
              
                Now provide a final helpful answer to the user.
              """

    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[{"role": "user", "content": prompt}]
    )

    return response.choices[0].message.content

最后就是将整个流程穿起来,咱们就得到一个多步决策智能体了:

def run_agent(query, tools, rag=None):
    print("=== Agent Start ===")
    print("User query:", query)

    decision = choose_tool(query, tools)
    print("Decision:", decision)

    tool_result = execute_tool(decision, tools, rag)
    print("Tool result:", tool_result)

    final_answer = generate_final_answer(query, tool_result)
    print("=== Agent End ===")

    return final_answer

这里有个小坑,咱们在选择工具的时候有写这样一段:

try:
	return json.loads(content)
except:
	return {"tool": "llm", "input": query}

所以咱们还需要再tool.py文件中补一个工具llm_tool

from datetime import datetime
from llm_utils import client


def rag_tool(query, rag):
    return rag.ask(query)


def calculator_tool(expression):
    try:
        return str(eval(expression))
    except:
        return "Invalid expression"


def time_tool(_):
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def llm_tool(query):
    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": query}
        ]
    )
    return response.choices[0].message.content


TOOLS = [
    {
        "name": "rag",
        "description": "Use for paper/document questions",
        "func": rag_tool
    },
    {
        "name": "calculator",
        "description": "Use for math calculations",
        "func": calculator_tool
    },
    {
        "name": "time",
        "description": "Use to get current time",
        "func": time_tool
    },
    {
        "name": "llm",
        "description": "Use for general questions",
        "func": llm_tool
    }
]

至此,咱们的代码升级完成,前面的咱们的代码是:

选工具 → 直接返回工具结果

到今天,咱们的代码实现了:

选工具 → 执行工具 → 工具结果作为 observation → LLM 再组织最终答案

如果这篇文章对你有帮助,可以点个赞~
完整代码地址:https://github.com/1186141415/A-Paper-Rag-Agent

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐