首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从产品级落地到架构内核:Agent 系统的分层解耦与最小内核实现

从产品级落地到架构内核:Agent 系统的分层解耦与最小内核实现

原创
作者头像
用户12339161
发布于 2026-10-13 16:28:27
发布于 2026-10-13 16:28:27
470
举报

核心结论: 产品级 Agent 的竞争力不在模型,而在内核是否把状态、权限、编排、执行四件事解耦。产品层只负责交互与任务定义,编排层用显式状态图控制流转,执行层用有界 Loop 调工具,基础设施层提供权限、审计与持久化。四层混在一起,Demo 能跑,生产必崩。

一、产品级落地的三个硬约束

任何直接 while True + messages 的实现,都会撞上三堵墙:

  1. 状态必须可恢复:任务中断后不能从头再来,中间结果要能持久化。
  2. 权限必须可审计:Agent 动了哪个文件、调了哪个 API,必须留痕。
  3. 行为必须可回放:出问题时能回溯“为什么走了这一步”,而不是只看到最终输出。

这三个约束决定了:产品层不能直接操作 LLM,必须通过内核。

二、架构内核四层

层

职责

对外接口

产品层

任务、工作空间、会话

kernel.run(task)

编排层

节点、边、状态机

Node / edges

执行层

Loop、工具、LLM

_step()

基础设施

权限、trace、存储

Permission / State

产品层只读 State.data 和 State.trace,不关心内部循环;内核升级不破坏产品,产品迭代不影响内核。

三、最小内核代码

以下内核不到 70 行,包含状态、权限、有界 Loop 与 trace。

代码语言:javascript
复制
from dataclasses import dataclass, field
from enum import Enum

class Kind(Enum):
    COLLECT, REASON, ACT, VERIFY = range(4)

@dataclass
class Node:
    id: str
    kind: Kind
    prompt: str
    tools: list[str] = field(default_factory=list)
    edges: dict[str, str | None] = field(default_factory=dict)
    max_iter: int = 5

@dataclass
class State:
    task: str
    data: dict = field(default_factory=dict)
    trace: list = field(default_factory=list)
    error: str | None = None

class Permission:
    def __init__(self, mode="workspace"):
        self.mode = mode
    def allow(self, tool: str, args: dict) -> bool:
        if self.mode == "readonly":
            return tool in ("read", "search", "glob")
        if self.mode == "workspace":
            path = args.get("path", "")
            return not path.startswith(("/etc", "C:\\Windows"))
        return True

class Kernel:
    def __init__(self, nodes, entry, llm, tools, perm, max_steps=20):
        self.nodes, self.entry = nodes, entry
        self.llm, self.tools, self.perm = llm, tools, perm
        self.max_steps = max_steps

    def run(self, task: str) -> State:
        st = State(task=task)
        cur = self.entry
        for step in range(self.max_steps):
            node = self.nodes[cur]
            out = self._step(node, st)
            st.trace.append({"step": step, "node": node.id, "out": out})
            cond = self._route(node, out)
            cur = node.edges.get(cond)
            if cur is None:
                break
        return st

    def _step(self, node, st):
        for _ in range(node.max_iter):
            ctx = {k: st.data.get(k) for k in self._reads(node)}
            act = self.llm.decide(node.prompt, ctx, node.tools)
            if act["kind"] == "done":
                st.data[self._writes(node)] = act["payload"]
                return act
            if not self.perm.allow(act["tool"], act.get("args", {})):
                st.error = "permission denied"
                return {"error": st.error}
            res = self.tools[act["tool"]](**act.get("args", {}))
            st.data.setdefault("_scratch", []).append(res)
        return {"error": "node_not_converged"}

    def _reads(self, node):
        return {
            Kind.COLLECT: [],
            Kind.REASON: ["collected"],
            Kind.ACT: ["hypotheses"],
            Kind.VERIFY: ["action_result"],
        }[node.kind]

    def _writes(self, node):
        return {
            Kind.COLLECT: "collected",
            Kind.REASON: "hypotheses",
            Kind.ACT: "action_result",
            Kind.VERIFY: "verified",
        }[node.kind]

    def _route(self, node, out):
        if out.get("error"):
            return "error"
        if node.kind == Kind.VERIFY:
            return "done" if out.get("ok") else "retry"
        return "ok"

四、产品层如何调用

代码语言:javascript
复制
nodes = {
    "collect": Node("collect", Kind.COLLECT, "读取数据源",
                    tools=["read", "query"],
                    edges={"ok": "reason", "error": None}),
    "reason": Node("reason", Kind.REASON, "列出 3 个假设",
                   edges={"ok": "act"}),
    "act": Node("act", Kind.ACT, "验证每个假设",
                tools=["query", "corr"],
                edges={"ok": "verify"}),
    "verify": Node("verify", Kind.VERIFY, "确认结论是否回答问题",
                   edges={"done": None, "retry": "reason"}),
}

kernel = Kernel(nodes, "collect", llm, tools, Permission("workspace"))
state = kernel.run("分析销售异常波动")
print(state.data.get("collected"))
for ev in state.trace:
    print(ev["node"], ev["out"])

产品层拿到 state.data 展示结果,拿 state.trace 做审计与回放。UI 不需要知道 Loop 怎么跑,只需要知道节点走到了哪。

五、工程化要点

第一,节点按工作性质分,不按步骤分。 读文件和读数据库同属 COLLECT,放一个节点;判断异常和提假设同属 REASON,放一个节点。

第二,回边必须有界。 verify → reason 这类回边受 max_iter 和 max_steps 双重限制,跑满未收敛就退出并报告 node_not_converged。

第三,状态是协议。 State 字段定义就是节点间接口契约,每个节点只读所需字段、只写负责字段,避免全量上下文传递。

第四,权限前置。 在工具执行前完成 Permission.allow 检查,而不是执行后补救。只读模式仅允许 read/search/glob,工作空间模式限制路径范围。

从产品级落地到架构内核,本质是把“模型会推理”和“外部世界需要确定接口”之间的矛盾,用分层解耦消化掉。内核越稳定,产品迭代越快。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、产品级落地的三个硬约束
  • 二、架构内核四层
  • 三、最小内核代码
  • 四、产品层如何调用
  • 五、工程化要点
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档