一文读懂NOAA架构:元类如何把"..."方法变成LLM智能体(源码级拆解)
【免费下载链接】labs-OO-AgentsNVIDIA Object Oriented Agents: the Pythonic way to build AI Agents.项目地址: https://gitcode.com/gh_mirrors/la/labs-OO-Agents
NOAA(NVIDIA Object Oriented Agents)是一个 Pythonic 的 AI Agent 框架,它用**元类(metaclass)**在类创建时自动识别方法体以...结尾的方法,并将其变成由 LLM 生成实现的"智能体方法"。本文从源码级拆解 NOAA 架构:AgentMeta元类如何扫描类命名空间、...标记如何用 AST 检测、以及调用时如何路由到生成策略——帮你快速理解 LLM 智能体框架的核心机制。
一句话的...如何变成 LLM 智能体?
传统 Agent 框架里,提示词、工具、回调、工作流是一堆零散的抽象。NOAA 的做法是:一个 Python 类 = 状态 + 能力 + 提示词 + 类型契约。
class SupportAgent(Agent): """You are a support agent.""" # 类文档字符串 = 系统提示词 order_db: OrderDB # 字段 = 状态 def is_refund_eligible(self, order: Order) -> bool: return order.delivered ... # 真实方法体 = 确定性 Python async def triage(self, message: str, order: Order) -> Ticket: """Create a typed support ticket.""" ... # "..." = 交给 LLM 实现- 有真实方法体 → 按普通 Python 运行;
- 以
...结尾的async def→ 变成"智能体方法",调用时由 LLM 生成实现并返回符合类型契约的结果。
你不需要工具注册表、图编译器或单独的调用 API——Python 类本身就是可执行定义(见 docs/architecture.md)。
NOAA 架构速览:从类定义到 LLM 生成的四个阶段 🧭
整个架构可以拆成四个阶段,对应仓库中的核心模块:
| 阶段 | 做什么 | 核心模块 |
|---|---|---|
| ① 类创建时 | 元类扫描方法,自动包装...方法 | src/nooa/metaclass.py |
| ② 识别阶段 | 用 AST 判断方法体是否以...结尾 | src/nooa/ellipsis_detection.py |
| ③ 调用阶段 | 统一 wrapper:参数校验、追踪、路由 | src/nooa/runtime/method_wrapper.py |
| ④ 生成阶段 | 策略驱动 LLM 生成实现(Predict / CodeAct) | src/nooa/strategies/ |
Agent基类通过class Agent(metaclass=AgentMeta)启用这一机制(见 src/nooa/agent.py),并设置_enable_tracing = True打开约定式追踪。
源码拆解①:AgentMeta 元类——类创建时的自动包装
核心入口是 AgentMeta.new:每个继承Agent的类被定义时,元类会遍历该类的命名空间,按方法形态分派:
- 异步生成器(
async def+yield)→ 仅加追踪 wrapper; - 协程函数(
async def)→ 若方法体是...则标记"需要生成",同时按需加追踪; - 同步方法(
def)→ 不能调用 LLM,只做追踪(双下划线方法直接跳过); property/classmethod/staticmethod不是普通函数,天然被跳过。
几个值得注意的设计:
- 约定优于配置:类上设置
_enable_tracing = True即启用追踪,方法上加 @no_trace 装饰器可单独退出; - 策略可覆盖:
@strategy装饰器会写入_strategy_override元数据,元类在 _resolve_strategy 中读取,否则运行期用默认策略; - 防御式校验:_reject_ellipsis_generator 会在类创建时直接报错——生成器方法(含
yield)不能用...标记,因为"生成"只产出单个最终结果,与流式语义矛盾; - 鸭子类型路由:包装后的方法不依赖
Agent类型。调用时若self有runtime属性就走 Agent 路径,否则直接调用原函数——这让元类也能用于策略类等非 Agent 对象。
源码拆解②:...是如何被精准识别的?
"这个方法需要 LLM 吗?"的判断逻辑在 src/nooa/ellipsis_detection.py:
- has_ellipsis_body 解析函数源码的AST:去掉文档字符串后,检查最后一条语句是否为
...。这意味着方法体可以在...之前写前置代码(如初始化变量),仍被视为生成方法; - get_pre_ellipsis_code 把
...之前的代码提取出来,作为"预置代码"保留给 LLM 生成流程; - 对动态生成的函数(无源码),回退到字节码启发式判断;
- has_ellipsis_marker 则更广,连
yield ...也算生成标记(用于生成器场景的报错提示)。
一句话总结:...不是 Python 的占位语法糖,而是 NOAA 自定义的"生成契约"——用 AST 精确识别,而非文本匹配。
源码拆解③:调用时,wrapper 如何路由?
方法被调用时,进入统一 wrapper(create_agent_method_wrapper)。它的职责链是:
- 参数校验:按签名校验实参,剥离框架保留的 kwargs;
- 解析策略:
@strategy覆盖 → 否则用默认策略(CodeAct); - 生成 LLM 调用 ID 与追踪属性:记录嵌套深度、父调用关系;
- 触发钩子:before/after agent call 中间件,产生事件与追踪 span;
- 交给运行时:由 runtime 组装上下文块、事件历史,驱动策略生成实现,并校验返回类型。
生成完成后,返回值会按方法签名做类型校验;校验失败会作为反馈返回给策略重试,而不是把非法值泄露给调用方。整个过程对外就是一个普通的await agent.triage(...)。
生成策略:...最终怎么变成真实实现?
策略层在 src/nooa/strategies/,两大主力:
- PredictStrategy(predict.py):一次性结构化输出尝试 + 类型校验,适合分类、抽取这类不需要工具的任务;
- CodeActStrategy(codeact.py):给模型一个 Jupyter 风格的 Python REPL,它通过写代码来行动——可以
self.xxx()调用可见方法、访问实时对象、使用工具,循环执行直到产出符合返回类型的结果。这是默认策略。
也就是说:元类负责"发现"...,wrapper 负责"调度",策略负责"实现"。三层分工清晰,也方便替换执行引擎(见 examples/advanced/swappable_execution_engines.py)。
三个常见坑与最佳实践 ⚠️
...必须是最后一条语句:写在中间或前面不会被识别为生成方法(文档字符串除外);- 生成器方法不能带
...:def/async def含yield再加...会在类定义时直接抛TypeError,这是刻意的快速失败设计; - 同步方法只会被追踪:
def方法不会触发 LLM 生成,需要异步 LLM 调用的逻辑请写成async def。
最佳实践:确定性逻辑写真实方法体(可测试、可缓存),把"需要判断力"的步骤留给...方法,并通过类型注解给 LLM 一个明确的输出契约。
快速上手:5 分钟写第一个 NOAA 智能体 🚀
pip install nooa # 或 uv add nooafrom nooa import Agent, llm class Analyst(Agent, llm=llm): async def classify(self, text: str) -> str: """Classify the text as positive or negative.""" ...想跟读官方教程,可以从 10 分钟巡礼 docs/tour.md 入手,第一个生成方法的完整示例见 examples/quickstart/01_first_generation_method.py,Agent 与方法的概念细节见 docs/concepts/agents-and-methods.md。
小结:NOAA 架构的精髓在于把"LLM 生成实现"这个动作收敛为一个元类 + 一个...标记——类创建时识别(AST)、调用时路由(wrapper)、运行时生成(策略),让 AI Agent 的开发回到最熟悉的 Python 类范式。读懂了 metaclass.py 这一个文件,NOAA 的核心机制你已经掌握了大半。
【免费下载链接】labs-OO-AgentsNVIDIA Object Oriented Agents: the Pythonic way to build AI Agents.项目地址: https://gitcode.com/gh_mirrors/la/labs-OO-Agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考