市面上常见的大模型,比如ChatGPT , deepseek之类的,他们具有思考能力,但是无法与外界进行感知,就是如果告诉GPT:帮我创建一个文档来实现一个100字的感谢信。GPT只能写出100子的感谢信,然后让你自己去创建文档复制粘贴。为了能够让大模型做到和外界交互,可以通过Tool来进行调用实现,这样的大模型 + Tool就构成了一个Agent

Agent的主要流程:

一般来讲使ReAct,即包括了:Thought , Action , Observation , final answer四个部分,对于前三个步骤进行循环。具体的:有两个主体:user和Agent,Agent又可以包括:大模型 , Tool , 主函数(run函数);user在提出需求,大模型进行Thought , 然后通过Action执行主函数调用Tool,然后结果返回大模型进行Observation,判断是否使final answer,如果是就返回结果,如果不是就重读前面的过程。

代码的实现:

import os
from openai import OpenAI
from dotenv import load_dotenv
import json

load_dotenv()
#LLM
client = OpenAI(
    api_key=os.getenv("OPENROUTER_API_KEY"),
    base_url="https://openrouter.ai/api/v1",
)

# tools
def read_file(file_path: str) -> str:
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"文件不存在: {file_path}")
    with open(file_path, "r", encoding="utf-8") as f:
        return f.read()

def write_file(file_path: str, content: str) -> str:
    os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
    with open(file_path, "w", encoding="utf-8") as f:
        f.write(content)
    return f"文件已写入: {file_path}"

def list_files(dir: str) -> str:
    files = [
        f for f in os.listdir(dir)
        if f.endswith(".js") and not f.endswith(".test.js")
    ]
    return "\n".join(files)

tool_handlers = {
    "read_file": lambda args: read_file(**args),
    "write_file": lambda args: write_file(**args),
    "list_files": lambda args: list_files(**args),
}


tools = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "读取指定路径的文件内容",
            "parameters": {
                "type": "object",
                "properties": {
                    "file_path": {"type": "string", "description": "文件路径"},
                },
                "required": ["file_path"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "将内容写入指定路径的文件",
            "parameters": {
                "type": "object",
                "properties": {
                    "file_path": {"type": "string", "description": "文件路径"},
                    "content": {"type": "string", "description": "文件内容"},
                },
                "required": ["file_path", "content"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "list_files",
            "description": "列出目录下所有 JS 文件",
            "parameters": {
                "type": "object",
                "properties": {
                    "dir": {"type": "string", "description": "目录路径"},
                },
                "required": ["dir"],
            },
        },
    },
]

SYSTEM_PROMPT = """你是一个专业的测试工程师。
规则:
1. 使用 Vitest 框架
2. 覆盖:正常输入、边界值、异常情况
3. 每个 it() 加注释说明测试意图
4. 只输出可直接运行的测试代码"""

# ReAct 循环
def generate_tests(target: str) -> str:
    is_dir = os.path.isdir(target)

    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": "请为 {target} 目录下所有 JS 文件生成测试"},
    ]
#Action
    while True:
        response = client.chat.completions.create(
            model="nvidia/nemotron-3-super-120b-a12b:free",
            max_tokens=4096,
            tools=tools,
            messages=messages,
        )

        choice = response.choices[0]
        message = choice.message
        messages.append(message)

        # finally
        if choice.finish_reason == "stop":
            return message.content

        # 调用工具
        if choice.finish_reason == "tool_calls":
            for tool_call in message.tool_calls:
                tool_name = tool_call.function.name
                tool_args = json.loads(tool_call.function.arguments)

                print(f"[Tool Call] {tool_name}", tool_args)

                try:
                    tool_result = tool_handlers[tool_name](tool_args)
                except Exception as e:
                    tool_result = f"错误: {str(e)}"

                print(f"[Tool Result] {tool_result}")

                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": str(tool_result),
                })

plan-excecute流程:

这个也是一个主要流程方式,和上面提到的ReAct不一样的在于:ReAct它包括一个大模型,而该流程包括两个大模型:plan模型和re-plan模型,即逐层规划查找问题

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐