一文搞懂Agent从手搓Claude开始

前段时间,写了一篇一文搞懂MCP、Function Calling和A2A,反响不错,一些有技术背景的朋友反馈说,通过代码和示例来理解抽象概念,比晦涩的原理介绍要直观易懂。鉴于此,我打算用同样的方式,写两篇文章系统地介绍一下Agent。本篇我会写两个Agent示例:通过计算器Agent,介绍如何用Deepseek开发Agent应用,及Agent使用工具的基本流程;通过简易版Claude编程Agent,介绍什么是ReAct(Reasoning+Acting),以及如何通过ReAct实现更加复杂的任务处理。

一个简单的计算器Agent

我们都知道LLM的本质是“文字接龙”,擅长语文,不擅长计算。本示例就是要开发一个简单的计算器Agent,让LLM把数学计算通过Function Calling委托给工具去实现。

使用Deepseek API

开发Agent,首先得有大模型服务。可用的MaaS(Model as a Service)很多,这里我选择deepseek,只需要去 https://api-docs.deepseek.com/zh-cn/ 注册,缴费(费用不用担心,2元/100万tokens,我用了几天才消耗1分钱),获取API key就可以访问了。关于API的使用,基本是和openAI的API兼容的(实际上,openai API已经是事实标准,这就是先发优势)。API不复杂,主要就两个REST接口:

  • 一个是获取所有模型的Get:https://api.deepseek.com/models ,

  • 另一个是调用模型的Post:https://api.deepseek.com/chat/completions

使用openai的SDK,我们可以用python写一个简单的程序,验证api的可用性:

from openai import OpenAI
client = OpenAI(
    api_key="<your API key>",
    base_url="https://api.deepseek.com",
    http_client=httpx.Client(verify=False) # 禁用 SSL 证书验证,测试使用
)

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Hello"},
  ],
    max_tokens=1024,
    temperature=0.7,
    stream=False# 不用流式(逐步返回生成的文本),处理简单
)

print(response.choices[0].message.content)

简单的计算器Agent

在这个Agent demo中,我们只提供了乘法、除法工具,以下是ai_agent_demo.py的全部代码:

import jsonimport reimport httpxfrom openai import OpenAI

# 定义计算工具函数def multiply(a, b):    """乘法工具"""    return float(a) * float(b)

def divide(a, b):    """除法工具"""    if float(b) == 0:        raise ValueError("除数不能为零")    return float(a) / float(b)

# 解析工具调用def parse_tool_call(tool_call):    """解析工具调用指令"""    pattern = r'<tool>([^<]*)</tool>'    match = re.search(pattern, tool_call)    if match:        return match.group(1).strip()    return None

# 执行工具调用def execute_tool(tool_command):    """执行工具命令并返回结果"""    try:        # 解析函数名和参数        if tool_command.startswith("multiply("):            # 提取参数            args_match = re.match(r'multiply\(([^,]+),\s*([^)]+)\)', tool_command)            if args_match:                a, b = args_match.groups()                result = multiply(a, b)                return f"<tool_output>{result}</tool_output>"
        elif tool_command.startswith("divide("):            # 提取参数            args_match = re.match(r'divide\(([^,]+),\s*([^)]+)\)', tool_command)            if args_match:                a, b = args_match.groups()                result = divide(a, b)                return f"<tool_output>{result}</tool_output>"
        return f"<tool_output>未知工具调用: {tool_command}</tool_output>"
    except Exception as e:        return f"<tool_output>工具执行错误: {str(e)}</tool_output>"

# 打印发送给AI的请求内容def print_messages(messages, iteration):    print("\n" + "=" * 50)    print(f"第 {iteration} 次API调用, 请求内容:")    print("=" * 50)
    # 打印整个messages的JSON内容    print(json.dumps(messages, indent=4, ensure_ascii=False))
    print("=" * 50)
# 调用大模型def invoke_model(user_input):    # 初始化客户端    client = OpenAI(        api_key="<your API key>",        base_url="https://api.deepseek.com",        http_client=httpx.Client(verify=False)    )
    # 工具使用说明    tool_use = """          当用户问计算相关问题,有必要可以使用工具,每个工具都是函数。    使用工具的方式为输出 "<tool>使用工具指令</tool>"。    使用工具后,你要等待回传结果 "<tool_output>工具回传的结果</tool_output>"。    最后,输出最终结果"<final_result>最终答案</final_result>"
    可用工具:    multiply(a,b): 返回 a 乘以 b    divide(a,b): 返回 a 除以 b    """
    # 初始化    messages = [        {"role": "system", "content": tool_use},        {"role": "user", "content": user_input},    ]
    max_iterations = 5  # 防止无限循环    iteration = 0    while iteration < max_iterations:        iteration += 1
        print_messages(messages, iteration)
        # 调用API        response = client.chat.completions.create(            model="deepseek-chat",            messages=messages,            stream=False        )
        assistant_content = response.choices[0].message.content        print(f"\nAI回复: {assistant_content}")
        # 检查是否需要工具调用        tool_command = parse_tool_call(assistant_content)
        if tool_command:            print(f"执行工具: {tool_command}")            tool_result = execute_tool(tool_command)            print(f"工具结果: {tool_result}")
            # 将工具结果添加到对话历史            messages.append({"role": "assistant", "content": assistant_content})            messages.append({"role": "user", "content": tool_result})
        else:            # 检查是否有最终结果            final_match = re.search(r'<final_result>([^<]*)</final_result>', assistant_content)            if final_match:                final_answer = final_match.group(1).strip()                print(f"\n🎉 最终答案: {final_answer}")            break    if iteration >= max_iterations:        print("⚠️  计算过程过于复杂,请简化您的问题。")

# 主函数def main():    print("AI计算助手已启动!输入计算问题或输入'退出'结束程序。")
    while True:        # 获取用户输入        user_input = input("\n请输入计算问题: ").strip()
        if user_input.lower() in ['退出', 'exit', 'quit']:            print("再见!")            break
        if not user_input:            continue
        invoke_model(user_input)

if __name__ == "__main__":    main()
程序的流程图如下图所示,关键就在于红框部分,Agent通过判断是否要使用工具,以及通过<final_result>判断是否要输出最终结果。

Agent运作过程解析

首先,我们用命令python ai_agent_demo.py启动Agent。 输入问题:123*45/23

接下来,我们通过Agent发送给LLM的request来分析Agent和LLM的交互过程。发送内容是一个JSON列表,主要包括三个role的信息,这些role分别代表:

  1. system代表系统角色

    ,content中是系统提示词(system prompt)

  2. user代表用户角色

    ,content中是用户输入(user input)

  3. assistant代表助手角色

    ,content中是AI助手的回复内容,这是历史对话的重要内容,assistant的content会帮助LLM知道它已经做了什么,这样它才知道接下去要做什么

对于算式123*45/23,我们的agent总共会和后端大模型交互三次:

1)首先,Agent会发送工具使用说明(system prompt)+ 用户问题(user prompt)给LLM。
第 1 次API调用,发送给LLM的内容:

[    {        "role": "system",        "content": " 当用户问计算相关问题...<工具使用说明>"    },    {        "role": "user",        "content": "123*45/23"    }]

LLM在接受到123*45/23后,知道这是一个先乘后除的运算,所以会先返回<tool>multiply(123,45)</tool>告诉Agent要使用乘法工具。

2)Agent在接受到LLM发送的工具调用请求<tool>multiply(123,45)</tool>之后,会调用multiply函数,并将调用结果<tool_output>5535.0</tool_output>连同之前的历史对话再次发给LLM。这里的关键是历史对话,因为大模型本身是无状态的,每次交互都是独立的,你提供的上下文就是它此次交互的全部世界。所以要把历史记录全部告诉LLM,这样它才知道已经做了什么,还要继续做什么。

第 2 次API调用,发送给LLM的内容:

[    {        "role": "system",         "content": " 当用户问计算相关问题...<工具使用说明>"    },    {        "role": "user",        "content": "123*45/23"    },    {        "role": "assistant",        "content": "<tool>multiply(123,45)</tool>"    },    {        "role": "user",        "content": "<tool_output>5535.0</tool_output>"    }]

所以从LLM的视角看来,上面的请求表达的意识是:用户提问了123*45/23, 我已经调用了工具<tool>multiply(123,45)</tool>,并且得到了工具调用结果<tool_output>5535.0</tool_output>,接下去,我应该计算5535/23了。

3)于是,Agent会再次收到LLM的工具调用反馈<tool>divide(5535.0,23)</tool>,并将计算结果<tool_output>240.652</tool_output>+历史记录发送给LLM
第 3 次API调用,发送给LLM的内容:

[    {        "role": "system",        "content": " 当用户问计算相关问题...<工具使用说明>"    },    {        "role": "user",        "content": "123*45/23"    },    {        "role": "assistant",        "content": "<tool>multiply(123,45)</tool>"    },    {        "role": "user",        "content": "<tool_output>5535.0</tool_output>"    },    {        "role": "assistant",        "content": "<tool>divide(5535.0,23)</tool>"    },    {        "role": "user",        "content": "<tool_output>240.652</tool_output>"    }]

LLM通过历史对话信息,已经执行了所有运算,用户的任务已完成。返回<final_result>240.652</final_result>标识本次任务完成。

ReAct

通过上面的案例,我相信你应该理解了Agent是如何使用工具的。为了进一步提升Agent的能力,ReAct(Reasoning And Acting)是被证明更加有效的任务处理框架。ReAct思想来自于这篇重要的论文:REAC T: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS(https://arxiv.org/abs/2210.03629)。论文中,作者有一个重要的洞察:我们人类在处理任务的时候有一个内心小剧场(Inner Speech),用语言的方式(Verbal Reasoning)指导我们已经做了什么(Working Memory),以及下一步要做什么。如果这个模式适用于人类,那么也会同样适用于LLM。论文通过实验证明了这一点,发现ReAct比COT(Chain Of Thought)和Act only要好很多。

把ReAct这个思维模式进行结构化,实际上就是Thought(思考) -> Action(行动) -> Observation(观察)三步的循环:

  1. Thought:模型分析当前情况,思考下一步该做什么,以及为什么要这么做。

  2. Action:基于思考,模型决定调用哪个工具,并生成具体的调用指令(如搜索查询)。

  3. Observation:工具执行后返回结果(如搜索引擎返回的摘要),模型接收这个结果作为新的信息。
    循环这三个步骤,每一轮,大模型都会结合Thought,Action,及Observation,进行下一轮的规划思考,直到用户任务得到最终解决。从而实现AI Agent(智能代理)。

举例说明ReAct模式

任务: “查一下苹果公司最新发布的iPhone有什么新功能,并总结成三点。”
在没有ReAct的模式下,模型可能直接基于训练数据中的旧信息生成一个答案,可能不准确。
在ReAct模式下,过程可能是这样的:

Thought 1:用户想知道苹果最新iPhone的新功能。我的内部知识可能不是最新的,所以我需要先用搜索引擎查找最新信息。我应该搜索“苹果最新iPhone发布 新功能”。
Action 1: Search[“苹果最新iPhone发布 新功能”]
Observation 1: 搜索引擎返回结果,显示苹果在2023年9月发布了iPhone 15系列,文章链接指向科技新闻网站。

Thought 2: 搜索结果显示是iPhone 15。我需要点开那个具体的文章链接来获取详细信息。
Action 2: Click[“https://example-tech-news.com/iphone15-review”]
Observation 2: 网页内容加载,详细介绍了iPhone 15的A16芯片、4800万像素主摄像头、灵动岛设计等。

Thought 3: 我已经获得了足够的信息。现在我需要从这些信息中提取最重要的三个新功能,并用简洁的语言总结给用户。
Action 3: Final Answer

  • 芯片升级

    :搭载了更强大的A16仿生芯片,性能提升显著。

  • 摄像系统革新

    :主摄像头升级至4800万像素,拍摄细节更丰富。

  • 全系启用灵动岛

    :取代了之前的刘海屏,提供全新的交互体验。

为什么ReAct模式如此重要

上面的示例展示了一个典型的使用工具获取最新产品信息的业务场景,RAG应该也能实现类似的效果。除此之外,ReAct还解决了LLM如下问题:

  1. 克服LLM的局限性:
  • 知识陈旧

    :通过调用搜索引擎,可以获取最新信息。

  • 缺乏精确计算能力

    :通过调用计算器或代码解释器,可以进行精确的数学运算。

  • “幻觉”问题

    :通过要求模型基于工具返回的事实(Observation)进行推理,减少了胡编乱造的可能。

  • 实现复杂任务自动化

    :它将AI从一个简单的聊天机器人,提升为一个可以自主操作软件、处理工作流的智能助手。例如,它可以自动“查看邮件 -> 提取数据 -> 录入表格 -> 生成报告”。

  • 提升透明度和可信度

    :由于整个思考过程被记录下来,用户可以清楚地看到AI是如何一步步解决问题的,这增加了结果的可靠性和可调试性。

  • 由此可见,Reasoning+Acting 是一种强大的AI范式,它通过将内部推理与外部行动相结合,使AI系统能够像智能代理一样,主动使用工具来解决超出其自身固有能力的复杂、现实世界任务。ReAct 是该模式在当今大语言模型领域最成功的实践,是构建下一代AI应用(如AI Agent)的核心技术基础。

    手搓一个简易版Claude

    一文搞懂MCP、Function Calling和A2A中,我曾用Cline Agent演示了MCP功能。实际上,Claude是目前最强大的coding agent。这些编程助手和LLM最大的差异在于,它们可以和环境交互,帮我们直接在IDE中写代码,review代码,提交MR等。作为编程Agent,它至少要包括读写文件,运行命令的能力。基于我们上面介绍的ReAct框架,我们现在也可以自己写一个简易版的Claude了。

    首先,我们需要一个教会大模型能用ReAct方式交互,且具备Function Calling能力的System prompt,该prompt我们可以将其单独放在prompt_template.py文件中。

    react_system_prompt_template = """
    你需要解决一个问题。为此,你需要将问题分解为多个步骤。对于每个步骤,首先使用 <thought> 思考要做什么,然后使用可用工具之一决定一个 <action>。接着,你将根据你的行动从环境/工具中收到一个 <observation>。持续这个思考和行动的过程,直到你有足够的信息来提供 <final_answer>。
    
    所有步骤请严格使用以下 XML 标签格式输出:
    - <question> 用户问题
    - <thought> 思考
    - <action> 采取的工具操作
    - <observation> 工具或环境返回的结果
    - <final_answer> 最终答案
    
    ⸻
    
    例子 1:
    
    <question>埃菲尔铁塔有多高?</question>
    <thought>我需要找到埃菲尔铁塔的高度。可以使用搜索工具。</thought>
    <action>get_height("埃菲尔铁塔")</action>
    <observation>埃菲尔铁塔的高度约为330米(包含天线)。</observation>
    <thought>搜索结果显示了高度。我已经得到答案了。</thought>
    <final_answer>埃菲尔铁塔的高度约为330米。</final_answer>
    
    ⸻
    
    请严格遵守:
    - 你每次回答都必须包括两个标签,第一个是 <thought>,第二个是 <action> 或 <final_answer>
    - 输出 <action> 后立即停止生成,等待真实的 <observation>,擅自生成 <observation> 将导致错误
    - 如果 <action> 中的某个工具参数有多行的话,请使用 \n 来表示,如:<action>write_to_file("/tmp/test.txt", "a\nb\nc")</action>
    - 工具参数中的文件路径请使用绝对路径,不要只给出一个文件名。比如要写 write_to_file("/tmp/test.txt", "内容"),而不是 write_to_file("test.txt", "内容")
    
    ⸻
    
    本次任务可用工具:
    ${tool_list}
    
    ⸻
    
    环境信息:
    
    操作系统:${operating_system}
    工作目录:${working_directory}
    工作目录下文件列表:${file_list}
    """

    react_agent.py是访问LLM并利用ReAct循环处理函数调用的核心类,其功能和上文介绍的计算Agent类似,只是在参数处理上会稍微复杂一些。

    import astimport inspectimport jsonimport osimport platformimport refrom string import Templatefrom typing import List, Callable, Tuple
    import httpxfrom openai import OpenAI
    from prompt_template import react_system_prompt_template
    
    class ReActAgent:    def __init__(self, tools: List[Callable], model: str, project_directory: str):        self.tools = {func.__name__: func for func in tools}        self.model = model        self.project_directory = project_directory        self.client = OpenAI(            base_url="https://api.deepseek.com",            api_key="<your API key>",            http_client=httpx.Client(verify=False),        )
    
        # 打印发送给AI的请求内容    def print_messages(self, messages, iteration):        print("\n" + "=" * 50)        print(f"第 {iteration} 次API调用, 请求内容:")        print("=" * 50)        # 打印整个messages的JSON内容        print(json.dumps(messages, indent=4, ensure_ascii=False))        print("=" * 50)
        def run(self, user_input: str):        messages = [            {"role": "system", "content": self.render_system_prompt(react_system_prompt_template)},            {"role": "user", "content": f"<question>{user_input}</question>"}        ]
            max_iterations = 10  # 防止无限循环        iteration = 0
            while iteration < max_iterations:            iteration += 1            self.print_messages(messages, iteration)
                # 请求模型            content = self.call_model(messages)
                # 检测 Thought            thought_match = re.search(r"<thought>(.*?)</thought>", content, re.DOTALL)            if thought_match:                thought = thought_match.group(1)                print(f"\n\n💭 Thought: {thought}")
                # 检测模型是否输出 Final Answer,如果是的话,直接返回            if "<final_answer>" in content:                final_answer = re.search(r"<final_answer>(.*?)</final_answer>", content, re.DOTALL)                return final_answer.group(1)
                # 检测 Action            action_match = re.search(r"<action>(.*?)</action>", content, re.DOTALL)            if not action_match:                raise RuntimeError("模型未输出 <action>")            action = action_match.group(1)            tool_name, args = self.parse_action(action)
                print(f"\n\n🔧 Action: {tool_name}({', '.join(args)})")            # 只有终端命令才需要询问用户,其他的工具直接执行            should_continue = input(f"\n\n是否继续?(Y/N)") if tool_name == "run_terminal_command" else "y"            if should_continue.lower() != 'y':                print("\n\n操作已取消。")                return "操作被用户取消"
                try:                observation = self.tools[tool_name](*args)            except Exception as e:                observation = f"工具执行错误:{str(e)}"            print(f"\n\n🔍 Observation:{observation}")            obs_msg = f"<observation>{observation}</observation>"            messages.append({"role": "user", "content": obs_msg})
        def get_tool_list(self) -> str:        """生成工具列表字符串,包含函数签名和简要说明"""        tool_descriptions = []        for func in self.tools.values():            name = func.__name__            signature = str(inspect.signature(func))            doc = inspect.getdoc(func)            tool_descriptions.append(f"- {name}{signature}: {doc}")        return "\n".join(tool_descriptions)
        def render_system_prompt(self, system_prompt_template: str) -> str:        """渲染系统提示模板,替换变量"""        tool_list = self.get_tool_list()        file_list = ", ".join(            os.path.abspath(os.path.join(self.project_directory, f))            for f in os.listdir(self.project_directory)        )        return Template(system_prompt_template).substitute(            operating_system=self.get_operating_system_name(),            working_directory=self.project_directory,            tool_list=tool_list,            file_list=file_list        )
        def call_model(self, messages):        print("\n\n正在请求模型,请稍等...")        response = self.client.chat.completions.create(            model=self.model,            messages=messages,        )        content = response.choices[0].message.content        messages.append({"role": "assistant", "content": content})        return content
        def parse_action(self, code_str: str) -> Tuple[str, List[str]]:        match = re.match(r'(\w+)\((.*)\)', code_str, re.DOTALL)        if not match:            raise ValueError("Invalid function call syntax")
            func_name = match.group(1)        args_str = match.group(2).strip()
            # 手动解析参数,特别处理包含多行内容的字符串        args = []        current_arg = ""        in_string = False        string_char = None        i = 0        paren_depth = 0
            while i < len(args_str):            char = args_str[i]
                if not in_string:                if char in ['"', "'"]:                    in_string = True                    string_char = char                    current_arg += char                elif char == '(':                    paren_depth += 1                    current_arg += char                elif char == ')':                    paren_depth -= 1                    current_arg += char                elif char == ',' and paren_depth == 0:                    # 遇到顶层逗号,结束当前参数                    args.append(self._parse_single_arg(current_arg.strip()))                    current_arg = ""                else:                    current_arg += char            else:                current_arg += char                if char == string_char and (i == 0 or args_str[i - 1] != '\\'):                    in_string = False                    string_char = None
                i += 1
            # 添加最后一个参数        if current_arg.strip():            args.append(self._parse_single_arg(current_arg.strip()))
            return func_name, args
        def _parse_single_arg(self, arg_str: str):        """解析单个参数"""        arg_str = arg_str.strip()
            # 如果是字符串字面量        if (arg_str.startswith('"') and arg_str.endswith('"')) or \                (arg_str.startswith("'") and arg_str.endswith("'")):            # 移除外层引号并处理转义字符            inner_str = arg_str[1:-1]            # 处理常见的转义字符            inner_str = inner_str.replace('\\"', '"').replace("\\'", "'")            inner_str = inner_str.replace('\\n', '\n').replace('\\t', '\t')            inner_str = inner_str.replace('\\r', '\r').replace('\\\\', '\\')            return inner_str
            # 尝试使用 ast.literal_eval 解析其他类型        try:            return ast.literal_eval(arg_str)        except (SyntaxError, ValueError):            # 如果解析失败,返回原始字符串            return arg_str
        def get_operating_system_name(self):        os_map = {            "Darwin": "macOS",            "Windows": "Windows",            "Linux": "Linux"        }
            return os_map.get(platform.system(), "Unknown")

    主程序入口claude_agent_demo.py

    import os
    import click
    from react_agent import ReActAgent
    
    def read_file(file_path):    """用于读取文件内容"""    with open(file_path, "r", encoding="utf-8") as f:        return f.read()
    
    def write_to_file(file_path, content):    """将指定内容写入指定文件"""    with open(file_path, "w", encoding="utf-8") as f:        f.write(content.replace("\\n", "\n"))    return "写入成功"
    
    def run_terminal_command(command):    """用于执行终端命令"""    import subprocess    run_result = subprocess.run(command, shell=True, capture_output=True, text=True)    return "执行成功" if run_result.returncode == 0 else run_result.stderr
    
    @click.command()@click.argument('project_directory',                type=click.Path(file_okay=False, dir_okay=True))def main(project_directory):    # 确保项目目录存在,如果不存在则创建    if not os.path.exists(project_directory):        os.makedirs(project_directory)
        project_dir = os.path.abspath(project_directory)
        tools = [read_file, write_to_file, run_terminal_command]    agent = ReActAgent(tools=tools, model="deepseek-chat", project_directory=project_dir)
        task = input("请输入任务:")
        final_answer = agent.run(task)
        print(f"\n\n✅ Final Answer:{final_answer}")
    
    if __name__ == "__main__":    main()

    使用我们自己的“Claude Agent”

    运行程序uv run claude_agent_demo.py snake 或者python claude_agent_demo.py snake 。后面的snake是参数,表示我们本次任务生成的代码会放在snake这个新建的目录之下。运行之后,我们会看到输入任务提示,假设我们要编写一个HTML的贪吃蛇游戏,可以输入以下信息。

    请输入任务:写一个贪吃蛇游戏,使用HTML,css和js实现,代码分别放在不同的文件中。

    运行结束以后,我们可以看到snake下面多出了三个文件,运行index.html,一个页面贪吃蛇游戏就可以玩了。

    我们退出程序。再次运行python claude_agent_demo.py snake,然后再次输入任务写一个贪吃蛇游戏,使用HTML,css和js实现,代码分别放在不同的文件中。 接下来会发生什么呢?

    此时,因为snake文件夹并不是空的,而是已经包含了实现贪吃蛇功能的index.html、script.js、style.css。所以LLM在面对这个新场景时,并不会直接去创建新的文件,而是看现有的程序是否OK,其对应的Thought如下:

    <Thought> 用户要求创建一个贪吃蛇游戏,需要分别用HTML、CSS和JS实现,并放在不同的文件中。我需要先查看当前工作目录中是否已有相关文件,然后根据需求创建或修改这些文件。</Thought>
    <Action> read_file(D:\code\COLA\demo-agent\snake\index.html)</Action>

    当LLM检查完所有三个文件以后,会生成以下的Thought:

    <Thought> 我已经检查了所有三个文件:index.html、style.css和script.js。看起来贪吃蛇游戏已经完整实现了,包括:
    1. HTML文件提供了游戏的基本结构和界面元素
    2. CSS文件提供了美观的样式设计
    3. JavaScript文件完整实现了贪吃蛇的游戏逻辑,包括:
       - 蛇的移动和控制
       - 食物的生成
       - 碰撞检测
       - 得分系统
       - 游戏结束处理
       - 重新开始功能
    </Thought>

    此时,已经无需更多的,LLM会直接返回<final_answer>:

    <final_answer>贪吃蛇游戏已经完整实现,用户可以使用方向键控制蛇的移动,吃到食物会增加分数,碰到墙壁或自身会结束游戏,可以点击重新开始按钮重新游戏。</final_answer>

    可以看到,这里的ReAct模式,特别是成功地处理了文件已存在的场景,避免了文件覆盖,或者其它不可预期的混乱。这里,我没有写任何处理“文件已存在”的代码,完全是大模型利用自己的Reasoning在解决这些预期之外的情况。更多细节,建议你运行一下上面的代码,通过日志,查看更多Agent和LLM的交互过程。

    总结

    实现一个基本的AI Agent很简单。首先,我们需要可用的LLM服务。其次,Agent要具备使用工具的能力。再次,Agent和LLM的每次交互必须要包含必要的对话历史,以提供足够的Context供LLM使用。参考人类任务处理的过程,使用ReAct模式可以极大的提升LLM解决问题的能力,所谓的ReAct就是循环让LLM用Thought(思考) -> Action(行动) -> Observation(观察)的方式处理用户任务,直到用户的问题得到解决。
    当然,Agent相关的技术还有很多,本文只是帮你建立基础的Agent认知。下一篇,我会介绍Langchain、RAG、记忆管理、Compaction等更高阶的Agent技术。

屋顶关键点检测数据集 一、基础信息 • 数据集名称:屋顶关键点检测数据集 • 图片数量: 训练集:864张图片 验证集:45张图片 测试集:37张图片 总计:946张图片 • 训练集:864张图片 • 验证集:45张图片 • 测试集:37张图片 • 总计:946张图片 • 分类类别: 类别0 • 类别0 • 标注格式: YOLO格式,包含关键点坐标标签,适用于关键点检测任务。 • YOLO格式,包含关键点坐标标签,适用于关键点检测任务。 • 数据格式:图片文件,来源于相关领域数据。 二、适用场景 • 建筑与航拍图像分析:用于检测屋顶结构的关键点,支持建筑评估、航拍数据处理等应用。 • 计算机视觉研究:适用于关键点检测算法的开发与测试,推动AI在特定领域的应用。 • 工业自动化:集成至自动化系统中,用于物体定位和结构分析。 • 学术与教育:作为关键点检测任务的教学数据集,帮助学生和研究人员理解相关技术。 三、数据集优势 • 单类别专注:数据集专注于单一类别(类别0)的关键点检测,便于模型学习和优化。 • 高质量标注:标注数据采用YOLO格式,关键点坐标精确,确保模型训练准确性。 • 数据量充足:提供近千张图片,覆盖多种场景,增强模型的鲁棒性。 • 即插即用:兼容YOLO等主流深度学习框架,可直接用于模型训练,节省预处理时间。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值