从零构建大模型智能体:OpenAI Function Calling智能体实战

引言

随着大语言模型逐步具备"理解---推理---行动"的能力,如何让模型稳定、可控地调用外部工具 ,已成为构建智能体(Agent)系统的关键一环。相比早期基于文本协议的工具调用方式,OpenAI 推出的 Function Calling(Tools)机制,为模型与程序世界之间建立了一套结构化、可验证的交互接口。

本文将从工程实践出发,完整展示一个 OpenAI 兼容 Function Calling 智能体 的实现过程:从消息协议(Message)、模型封装(ChatOpenAI)、工具抽象(Tool),到支持多轮、多工具调用的 Agent 主循环设计。通过真实的搜索与计算场景示例,你将看到模型如何在最少提示干预的情况下,自主规划、调用工具并整合结果,最终给出可靠答案。

如果你希望构建一个可扩展、可调试、可流式演进的 Agent 系统,本文的实现将是一个坚实的起点。

代码: vero

Message类

为了兼容OpenAI的消息格式,我们重写一下Message类:

py 复制代码
from typing import Dict, Any, Optional, List, Self, Union, Literal
import time
from pydantic import BaseModel, Field


class Message(BaseModel):
    content: Optional[Union[str, List[Dict[str, Any]]]] = None
    role: Literal["system", "user", "assistant", "tool"]
    name: Optional[str] = None
    tool_call_id: Optional[str] = None
    tool_calls: Optional[List[Dict[str, Any]]] = None
    timestamp: int = Field(default_factory=lambda: int(time.time()))
    metadata: Dict[str, Any] = Field(
        default_factory=dict, description="token counts"
    )

    @classmethod
    def user(cls, content: str, **kw) -> Self:
        return cls(role="user", content=content, **kw)

    @classmethod
    def system(cls, content: str, **kw) -> Self:
        return cls(role="system", content=content, **kw)

    @classmethod
    def assistant(
        cls, content: Optional[str] = None, tool_calls: List[dict] = None, **kw
    ) -> Self:
        return cls(role="assistant", content=content, tool_calls=tool_calls, **kw)

    @classmethod
    def tool(cls, content: str, tool_call_id: str, **kw) -> Self:
        return cls(
            role="tool",
            content=content,
            tool_call_id=tool_call_id,
            **kw,
        )

    def to_dict(self) -> Dict[str, Any]:
        d = {
            k: v
            for k, v in self.__dict__.items()
            if k not in ("timestamp", "metadata") and v is not None
        }

        return d

ChatOpenAI类

同时,我们封装了工具调用的入参和出参,就像上篇文章中介绍的一样:

py 复制代码
from typing import Optional, Iterator, List, Union, Dict, Any
from openai import OpenAI

from .message import Message
from vero.config import settings
from vero.core.exceptions import LLMCallError, LLMConfigError


class ChatOpenAI:
    """
    基于 OpenAI Python SDK 的聊天模型封装,用于与对话式 LLM 进行交互。

    属性:
        model_name: 使用的 LLM 模型名称。
        temperature: 文本生成的采样温度。
        max_tokens: 单次响应的最大 token 数。
        timeout: 请求超时时间(秒)。
        api_key: OpenAI API Key。
        base_url: OpenAI API Base URL。
    """

    def __init__(
        self,
        model_name: Optional[str] = None,
        api_key: Optional[str] = None,
        base_url: Optional[str] = None,
        temperature: float = 0.7,
        max_tokens: Optional[int] = None,
        timeout: Optional[int] = None,
        **kwargs,
    ) -> None:
        """
        初始化 LLM 封装类。
        如果未显式传入参数,则回退到配置文件中的默认值。

        Raises:
            LLMConfigError: 当缺少 api_key、base_url 或 model_name 时抛出。
        """

        self.model_name = model_name or settings.model_name
        print(f"🤖 Initializing LLM with model: {self.model_name}")

        self.temperature = temperature
        self.max_tokens = max_tokens
        self.timeout = timeout or getattr(settings, "timeout", None)
        self.kwargs = kwargs

        self.api_key = api_key or settings.openai_api_key
        self.base_url = base_url or settings.openai_base_url

        if not all([self.api_key, self.base_url, self.model_name]):
            raise LLMConfigError(
                "Missing api_key, base_url, or model_name for LLM client"
            )

        self._client = self._create_client()

    def _create_client(self) -> OpenAI:
        """
        创建并返回 OpenAI 客户端实例。
        """
        return OpenAI(
            api_key=self.api_key,
            base_url=self.base_url,
            timeout=self.timeout,
        )

    def generate(
        self,
        messages: List[Union[Message, dict]],
        stream: bool = False,
        temperature: Optional[float] = None,
        tools: Optional[List[dict]] = None,
        tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
        **kwargs,
    ) -> Union[Message, Iterator[str]]:
        """
        调用 LLM 生成响应,支持流式输出与非流式完整输出。

        Args:
            messages: 对话历史消息列表,可以是 Message 对象或原始 dict。
            stream: 是否启用流式输出;为 True 时返回一个迭代器。
            temperature: 可选参数,用于覆盖默认 temperature。
            tools: OpenAI Tool / Function Calling 的 schema 定义。
            tool_choice: 工具选择策略("auto"、"none" 或指定工具)。
            **kwargs: 其他 OpenAI 参数(如 max_tokens)。

        Returns:
            Message:
                非流式场景下返回 Assistant Message。
                若模型触发了工具调用,tool_calls 会挂载在 Message 上,
                此时 content 可能为 None。
            Iterator[str]:
                流式模式下,按 token / chunk 迭代返回生成文本。

        Raises:
            LLMCallError: 当 LLM API 调用失败时抛出。
        """
        # 将 Message 对象统一转换为 OpenAI API 可接受的 dict 结构
        messages_dict = [
            msg.to_dict() if isinstance(msg, Message) else msg
            for msg in messages
        ]

        try:
            # 构造基础请求参数
            payload = {
                "model": self.model_name,
                "messages": messages_dict,
                "temperature": temperature or self.temperature,
                "max_tokens": kwargs.get("max_tokens", self.max_tokens),
            }

            # 如果提供了 tools / tool_choice,则注入到请求中
            if tools:
                payload["tools"] = tools
            if tool_choice:
                payload["tool_choice"] = tool_choice

            # 透传其他 OpenAI 支持的参数
            for k, v in kwargs.items():
                if k not in {"temperature", "max_tokens"}:
                    payload[k] = v

            response = self._client.chat.completions.create(
                stream=stream,
                **payload,
            )

            if stream:
                # 使用内部生成器封装流式响应
                # 避免整个 generate 方法本身变成 generator
                def _stream_generator():
                    for chunk in response:
                        content = chunk.choices[0].delta.content or ""
                        if content:
                            yield content

                return _stream_generator()

            # -----------------------------
            # 非流式模式:构造 Message 对象
            # -----------------------------
            resp_msg = response.choices[0].message
            usage = response.usage or {}

            assistant_msg = Message.assistant(
                content=resp_msg.content,
                metadata={
                    "usage": {
                        "prompt_tokens": usage.prompt_tokens,
                        "completion_tokens": usage.completion_tokens,
                        "total_tokens": usage.total_tokens,
                    }
                },
            )

            # 处理 Function / Tool Calling 结果(如果存在)
            if resp_msg.tool_calls:
                assistant_msg.tool_calls = [
                    {
                        "id": call.id,
                        "type": "function",
                        "function": {
                            "name": call.function.name,
                            "arguments": call.function.arguments,
                        },
                    }
                    for call in resp_msg.tool_calls
                ]

            return assistant_msg

        except Exception as e:
            # 统一封装为自定义异常,便于上层处理
            raise LLMCallError(f"LLM call failed: {str(e)}") from e

Tool类

主要增加to_openai_schema()方法可以转换为上篇文章看到的OpenAI兼容的JSON Schema定义:

py 复制代码
import inspect
from typing import Any, Dict, List, Optional, Union, get_origin, get_args


class Tool:
    """
    表示一个可被 LLM 智能体系统调用的工具(函数封装)。

    该 Tool 同时支持:
    1. 人类可读的描述(name / description)
    2. Python 直接调用(__call__)
    3. OpenAI  Function Calling Schema
    """

    # Python 类型到 JSON Schema 类型的映射
    PYTHON_TO_JSON = {
        str: "string",
        int: "integer",
        float: "number",
        bool: "boolean",
        dict: "object",
        list: "array",
    }

    def __init__(
        self,
        name: str,
        description: str,
        func: callable,
        arguments: list,
        outputs: str,
    ):
        self.name = name
        self.description = description
        self.func = func
        self.arguments = arguments  # [(param_name, type_str, default), ...]
        self.outputs = outputs

        # 同时保留 signature,方便生成 Function Calling schema
        self.signature = inspect.signature(func)

    def __call__(self, *args, **kwargs):
        """
        直接调用底层的 Python 函数
        """
        return self.func(*args, **kwargs)

    def to_string(self) -> str:
        """
        返回一个人类可读的工具描述字符串(主要用于调试或日志)
        """
        args_str = ", ".join(
            [
                f"{n}: {t}" + (f" = {d}" if d is not None else "")
                for (n, t, d) in self.arguments
            ]
        )

        return (
            f"Tool Name: {self.name}, "
            f"Description: {self.description}, "
            f"Arguments: {args_str}, "
            f"Outputs: {self.outputs}"
        )

    # ================================
    # OpenAI Function Calling
    # ================================
    def to_openai_schema(self) -> dict:
        """
        将当前 Tool 转换为 OpenAI / Qwen 兼容的 Function Calling Schema。

        返回格式示例:
        {
          "type": "function",
          "function": {
            "name": "...",
            "description": "...",
            "parameters": {
              "type": "object",
              "properties": {...},
              "required": [...]
            }
          }
        }
        """
        properties: Dict[str, Any] = {}
        required: List[str] = []

        for name, param in self.signature.parameters.items():
            if name == "self":
                continue

            annotation = param.annotation
            default = None if param.default is inspect._empty else param.default

            schema, is_required = self._annotation_to_schema(annotation, default)

            # OpenAI 要求每个参数都有 description
            schema["description"] = name

            properties[name] = schema
            if is_required:
                required.append(name)

        parameters = {
            "type": "object",
            "properties": properties,
            "required": required,
            # 如果你希望严格模式,可打开:
            # "additionalProperties": False,
        }

        return {
            "type": "function",
            "function": {
                "name": self.name,
                "description": self.description or "",
                "parameters": parameters,
            },
        }

    def _annotation_to_schema(self, annotation: Any, default: Any):
        """
        将 Python 类型注解转换为 JSON Schema,并判断参数是否必填
        """
        origin = get_origin(annotation)
        args = get_args(annotation)

        # Optional[T] 或 Union[T, None] → 非必填
        if origin is Union and type(None) in args:
            non_none = [a for a in args if a is not type(None)]
            if len(non_none) == 1:
                inner_schema, _ = self._annotation_to_schema(non_none[0], None)
                return {
                    "anyOf": [inner_schema, {"type": "null"}]
                }, False

        # List[T]
        if origin in (list, List):
            item_type = args[0] if args else Any
            item_schema, _ = self._annotation_to_schema(item_type, None)
            return {
                "type": "array",
                "items": item_schema,
            }, default is None

        # Dict[str, T]
        if origin in (dict, Dict):
            value_type = args[1] if len(args) == 2 else Any
            value_schema, _ = self._annotation_to_schema(value_type, None)
            return {
                "type": "object",
                "additionalProperties": value_schema,
            }, default is None

        # 基础类型
        if annotation in self.PYTHON_TO_JSON:
            return {
                "type": self.PYTHON_TO_JSON[annotation]
            }, default is None

        # 兜底:无法识别的类型统一视为 string
        return {"type": "string"}, default is None


def tool(func):
    """
    装饰器:将普通 Python 函数转换为 Tool 对象。

    自动解析:
    - 函数名
    - 参数名 / 类型 / 默认值
    - 返回值类型
    - 函数 docstring 作为工具描述
    """

    signature = inspect.signature(func)
    arguments = []

    # 解析参数信息(主要用于人类可读)
    for param in signature.parameters.values():
        annotation = param.annotation
        type_str = (
            annotation.__name__
            if hasattr(annotation, "__name__")
            else str(annotation)
        )

        default = None if param.default is inspect._empty else param.default
        arguments.append((param.name, type_str, default))

    # 解析返回值类型
    return_annotation = signature.return_annotation
    if return_annotation is inspect._empty:
        outputs = "None"
    else:
        outputs = (
            return_annotation.__name__
            if hasattr(return_annotation, "__name__")
            else str(return_annotation)
        )

    description = inspect.getdoc(func) or "未提供工具描述"
    name = func.__name__

    return Tool(
        name=name,
        description=description,
        func=func,
        arguments=arguments,
        outputs=outputs,
    )

Function Calling 智能体

终于可以进入本文的主题,我们实现一个通过Function Calling进行工具调用的智能体。

如果看完了最近的几篇文章,理解下面的代码应该不难:

py 复制代码
import json
import time
from typing import Optional, List, Dict, Any

from vero.tool import Tool
from vero.core.message import Message
from vero.core.chat_openai import ChatOpenAI
from vero.core.agent import Agent
from vero.core.exceptions import ToolNotFoundError


class OpenAIFunctionAgent(Agent):
    """
    一个支持 OpenAI 兼容 Function Calling(tools)的 Agent 实现。

    特性:
        - 支持在单个 assistant 消息中包含多个 tool_calls
        - 自动执行模型请求的工具
        - 将工具执行结果自动注入回对话上下文
        - 持续循环,直到模型输出最终的纯文本答案
    """

    def __init__(
        self,
        name: str,
        llm: ChatOpenAI,
        tools: Optional[List[Tool]] = None,
        system_prompt: Optional[str] = None,
        max_turns: int = 5,
        tool_choice: str = "auto",
    ) -> None:
        """
        初始化 OpenAIFunctionAgent。

        参数:
            name: Agent 的可读名称标识。
            llm: 用于推理的 ChatOpenAI 实例。
            tools: 可选的 Tool 列表,表示 Agent 可调用的工具。
            system_prompt: 可选的 system prompt 覆盖文本。
            max_turns: 最大推理 / 工具执行循环次数。
            tool_choice: OpenAI 的 tool_choice 参数("auto"、"none" 或强制指定工具)。
        """
        print(f"🚀 Initializing OpenAIFunctionAgent `{name}` ...")

        super().__init__(
            name=name,
            llm=llm,
            tools=tools,
            system_prompt=system_prompt,
            max_turns=max_turns,
        )

        self.tool_choice = tool_choice
        self.tools_schema = self._build_tool_schemas()

        print(f"🛠️ Registered tools: {self.tools}")
        print(f"⚙️ Tool choice mode: {self.tool_choice}")

        # 使用 system prompt 初始化对话历史
        self.add_message(Message.system(self._build_system_prompt()))

    # ------------------------------------------------------------------
    # System prompt
    # ------------------------------------------------------------------
    def _build_system_prompt(self) -> str:
        """
        构建 Agent 使用的 system prompt。
        """
        return (
            self.system_prompt
            or "You are an intelligent agent capable of using external tools to help solve user queries."
        )

    # ------------------------------------------------------------------
    # Tool schemas
    # ------------------------------------------------------------------
    def _build_tool_schemas(self) -> List[Dict[str, Any]]:
        """
        将已注册的 Tool 转换为 OpenAI 兼容的 function calling schema。
        """
        if not self.tools:
            return []
        return [t.to_openai_schema() for t in self.tools]

    # ------------------------------------------------------------------
    # Main execution loop
    # ------------------------------------------------------------------
    def run(self, user_query: str) -> str:
        """
        执行 Agent 的主推理循环。

        执行步骤:
            1. 将用户输入追加到对话历史
            2. 携带工具 schema 调用 LLM
            3. 如果 assistant 返回了 tool_calls:
                - 逐个执行工具
                - 将工具结果以 Message.tool 的形式注入历史
            4. 重复以上过程,直到模型返回纯文本结果
        """
        print("\n==============================")
        print(f"👤 User Input: {user_query}")
        print("==============================\n")

        self.add_message(Message.user(user_query))

        for turn_idx in range(1, self.max_turns + 1):
            print(f"🔁 Turn {turn_idx}/{self.max_turns}")

            assistant_msg: Message = self.llm.generate(
                messages=self._history,
                tools=self.tools_schema,
                tool_choice=self.tool_choice,
            )

            print(
                f"📤 LLM Assistant Message | "
                f"content={assistant_msg.content!r}, "
                f"tool_calls={bool(assistant_msg.tool_calls)}"
            )

            self.add_message(assistant_msg)

            # -------------------------------------------------
            # 情况 A:最终文本回复(无工具调用)
            # -------------------------------------------------
            if not assistant_msg.tool_calls:
                print("💬 未检测到工具调用,返回最终答案。\n")
                return assistant_msg.content or ""

            # -------------------------------------------------
            # 情况 B:检测到工具调用
            # -------------------------------------------------
            for tc in assistant_msg.tool_calls:
                func = tc["function"]
                tool_name = func["name"]
                args_text = func["arguments"]
                tool_call_id = tc["id"]

                print(
                    f"🧩 检测到工具调用 → "
                    f"name={tool_name}, id={tool_call_id}, raw_args={args_text}"
                )

                # 解析参数(OpenAI 保证 arguments 为 JSON 字符串)
                try:
                    args = json.loads(args_text)
                    print("📦 工具参数解析成功。")
                except Exception as e:
                    print(f"❌ 工具参数解析失败: {e}")
                    args = {}

                # 查找工具对象
                tool: Tool | None = self.tool_by_names.get(tool_name)
                if not tool:
                    print("❌ 未找到对应工具!")
                    raise ToolNotFoundError(f"Unknown tool: {tool_name}")

                # 执行工具
                print(f"🔧 执行工具 `{tool_name}`,参数={args}")
                try:
                    start = time.perf_counter()
                    output = tool(**args)
                    cost = time.perf_counter() - start
                    print(f"📦 工具输出: {output} | ⏱️ 耗时: {cost:.3f}s")
                except Exception as e:
                    output = f"Tool execution failed: {e}"
                    print(f"💥 工具执行失败: {e}")

                # 将工具结果注入回对话历史
                print("📥 将工具结果注入对话历史。")
                self.add_message(
                    Message.tool(
                        content=str(output),
                        tool_call_id=tool_call_id,
                    )
                )

            # 继续下一轮,让模型基于工具结果继续推理

        raise RuntimeError("已达到 max_turns,但仍未生成最终答案")

函数调用智能体实战

py 复制代码
import time

from vero.core import ChatOpenAI, Agent
from vero.agents import SimpleAgent, OpenAIFunctionAgent
from vero.tool.buildin import math_evaluate, duckduckgo_search
from vero.config import settings


def run_agent(agent_class: Agent, input_text: str, max_turns=5):
    llm = ChatOpenAI()
    
    agent: Agent = agent_class(
        "test-agent",
        llm,
        tools=[duckduckgo_search, math_evaluate],
        max_turns=max_turns,
    )

    return agent.run(input_text)


if __name__ == "__main__":
    settings.model_name = "Qwen/Qwen3-30B-A3B-Instruct-2507"
    start = time.perf_counter()
    answer = run_agent(
        OpenAIFunctionAgent,
        "2025年12月13日为止,国内票房最高的三部动画片是什么?导演分别是谁?",
    )
    print(f"🏁 Final LLM Answer: {answer}\n")

    print(f"⏳ Elapsed: {time.perf_counter() - start:.1f} s")
复制代码
🤖 Initializing LLM with model: Qwen/Qwen3-30B-A3B-Instruct-2507
🚀 Initializing OpenAIFunctionAgent `test-agent` ...
🛠️ Registered tools: [<Tool duckduckgo_search>, <Tool math_evaluate>]
⚙️ Tool choice mode: auto

==============================
👤 User Input: 2025年12月13日为止,国内票房最高的三部动画片是什么?导演分别是谁?
==============================

🔁 Turn 1/5
📤 LLM Assistant Message | content='', tool_calls=True
🧩 Tool call detected → name=duckduckgo_search, id=019b17e045acef53358fa8ae588ace97, raw_args={"query": "2025年12月13日 国内票房最高的三部动画片 导演", "max_results": 5}
📦 Tool arguments parsed successfully.
🔧 Executing tool `duckduckgo_search` with args={'query': '2025年12月13日 国内票房最高的三部动画片 导演', 'max_results': 5}
📦 Tool output: Title: 中国内地最高电影票房收入列表 - 维基百科,自由...
Link: https://zh.wikipedia.org/zh-hans/中国内地最高电影票房收入列表
Snippet: 2 days ago - 下列为电影作品在中国内地电影院上映的票房收入相关列表。票房收入以人民币为单位,不考虑通货膨胀因素,仅以当时售价计量。 ... 下表罗列了2015年《捉妖记》成为中国内地电影总票房冠军之前的华语电影总票房记录...

Title: 哪吒之魔童闹海 - 维基百科,自由的百科全书
Link: https://zh.wikipedia.org/zh-hans/哪吒之魔童闹海
Snippet: 2 weeks ago - 社会人士方面,游戏科学创办人冯骥对本片予以推荐,称本片的故事和技术达到全球顶尖水准,足以称为"国产动画片天花板"。影评人周黎明认为本片依托经典神话的创新改编精准触达年轻群体,其成功源于文化共鸣而非单纯政策激励。《环球时报》前总编辑胡锡进则将本片视为中国动画工业化里程碑,称"中国人仰望《功夫熊猫》那些好莱坞动画片并啧啧称奇的时代结束了"。导演陶海认为本片重视剧本创作但仍有提升空间,表示"'发狠'的人物动机以及'硬拔'式的情节推动是剧作大忌"。漫画家郭竞雄肯定了该片在技术上的成功,但批评其带有"粉红战狼思维"和"抖音化认知"。

Title: 影片总票房排行榜
Link: https://piaofang.maoyan.com/rankings/year
Snippet: 全部 · 2025年 · 2024年 · 2023年 · 2022年 · 2021年 · 2020年 · 2019年 · 2018年 · 2017年

Title: 全球动画电影票房榜
Link: https://piaofang.maoyan.com/i/globalBox/realtimeRank/anime
Snippet: 全球动画电影票房榜 · 2025-12-08 13:26:19 更新 · 影片排名 · 含预售总票房(单位:元) · 哪吒之魔童闹海 · 2025-1-29 中国大陆首映 · 159.49亿 · 中国(含港澳台) · 海外 · 155.05亿

Title: 2025年动画电影为何能够"三连爆"?-中新网
Link: https://www.chinanews.com.cn/cul/2025/12-02/10525112.shtml
Snippet: 电影市场迎来了"动画大年"。2025年的年初、年中、年末,《哪吒之魔童闹海》(以下简称《哪吒2》)、《浪浪山小妖怪》(以下简称《小妖怪》)、《疯狂动物城2》(以下简称《动物城2》)三部动画电影破圈。 · 《哪吒2》以154.46亿元的票房成为中国影史票房榜冠军、全球影史动画票房榜冠军,同时位列2025年全球影史票房榜第五。《小妖怪》以17.19亿元的票房,成为中国2D动画电影票房冠军。《动物城2》上映6日票房突破20亿元(截至12月1日记者发稿数据),成为中国影史进口动画票房冠军,该影片单日吸金突破7亿元,多个平台预测《动物城2》在中国的票房有望突破40亿元。
 | ⏱️ Cost: 1.217s
📥 Injecting tool result into conversation history.
🔁 Turn 2/5
📤 LLM Assistant Message | content='根据截至2025年12月13日的票房数据,中国内地票房最高的三部动画片及其导演如下:\n\n1. **《哪吒之魔童闹海》(简称《哪吒2》)**  \n   - **票房**:159.49亿元人民币  \n   - **导演**:饺子(原名杨宇)  \n   - **备注**:该片不仅成为中国影史票房冠军,也位列全球影史动画电影票房榜首,是2025年全球票房第五的影片。\n\n2. **《浪浪山小妖怪》(简称《小妖怪》)**  \n   - **票房**:17.19亿元人民币  \n   - **导演**:李炜  \n   - **备注**:该片是中国2D动画电影票房的冠军,凭借独特的画风与情感共鸣获得广泛好评。\n\n3. **《疯狂动物城2》(简称《动物城2》)**  \n   - **票房**:预计突破40亿元人民币(截至12月13日已超20亿元,上映仅6天即突破20亿)  \n   - **导演**:拜伦·霍华德(Byron Howard)、里奇·摩尔(Rich Moore)  \n   - **备注**:作为进口动画电影,该片成为中国影史进口动画票房冠军,单日票房曾突破7亿元。\n\n> 📌 **说明**:以上信息综合自猫眼专业版、维基百科及中新社报道,数据截至2025年12月13日,其中《动物城2》仍在上映中,最终票房可能进一步上升。', tool_calls=False
💬 No tool calls detected. Returning final answer.

🏁 Final LLM Answer: 根据截至2025年12月13日的票房数据,中国内地票房最高的三部动画片及其导演如下:

1. **《哪吒之魔童闹海》(简称《哪吒2》)**  
   - **票房**:159.49亿元人民币  
   - **导演**:饺子(原名杨宇)  
   - **备注**:该片不仅成为中国影史票房冠军,也位列全球影史动画电影票房榜首,是2025年全球票房第五的影片。

2. **《浪浪山小妖怪》(简称《小妖怪》)**  
   - **票房**:17.19亿元人民币  
   - **导演**:李炜  
   - **备注**:该片是中国2D动画电影票房的冠军,凭借独特的画风与情感共鸣获得广泛好评。

3. **《疯狂动物城2》(简称《动物城2》)**  
   - **票房**:预计突破40亿元人民币(截至12月13日已超20亿元,上映仅6天即突破20亿)  
   - **导演**:拜伦·霍华德(Byron Howard)、里奇·摩尔(Rich Moore)  
   - **备注**:作为进口动画电影,该片成为中国影史进口动画票房冠军,单日票房曾突破7亿元。

> 📌 **说明**:以上信息综合自猫眼专业版、维基百科及中新社报道,数据截至2025年12月13日,其中《动物城2》仍在上映中,最终票房可能进一步上升。

⏳ Elapsed: 12.8 s
相关推荐
XiaoMu_0018 小时前
基于深度学习的农作物叶片病害智能识别与防治系统
人工智能·深度学习
potato_15548 小时前
Windows11系统安装Isaac Sim和Isaac Lab记录
人工智能·学习·isaac sim·isaac lab
测试人社区-千羽8 小时前
48小时攻克测试岗——闪电面试极速备战手册
人工智能·python·opencv·面试·职场和发展·单元测试·压力测试
独自归家的兔8 小时前
大模型通义千问3-VL-Plus - 视觉推理(在线视频)
人工智能·计算机视觉
qq_160144879 小时前
2025年AI工程师认证报考指南:上海站最新流程
人工智能
Coding茶水间9 小时前
基于深度学习的脑肿瘤检测系统演示与介绍(YOLOv12/v11/v8/v5模型+Pyqt5界面+训练代码+数据集)
人工智能·深度学习·yolo·目标检测·机器学习·计算机视觉
L.EscaRC9 小时前
【AI基础篇】认识RNN
人工智能·rnn·深度学习
Vantastic9999 小时前
基于Qwen Agent的多智能体协作系统:实现AI团队协同工作流
人工智能·python
Tezign_space9 小时前
抖音AI运营工具技术实践:特赞内容矩阵架构与300%效率提升方案
人工智能·架构·aigc·内容运营·抖音·ai营销工具·特赞