第 5 章 Agent 抽象:从大模型调用到「人格化」助手

上一章我们从「会话」的角度,解决了「这条消息属于谁、属于哪次对话」的问题。本章要回答的是下一个自然而然的问题:该让哪一个 Agent 来处理它?以及,这个 Agent 到底是什么东西?

5.1 为什么需要 Agent 抽象:从「裸模型」到「人格化助手」

如果你直接把用户的问题丢给一个大模型(例如 Claude 或 GPT),最多也就是一次性传入一些系统提示词,加上一两段用户背景信息,再告诉它可以调用哪些工具。这种「裸模型接工具」的方式,简单场景下当然够用,但稍微往前走一步就会碰壁。

不同的任务需要完全不同的角色设定与工具集——代码助手和生活助理的行为期待天差地别。不同的渠道和用户对安全边界、语气也各有各的要求。更麻烦的是,想要持久地「调教」一个助手,不断改进它的行为,在裸模型方案里几乎无从下手。

Agent 抽象要做的,就是在「裸模型 + 工具列表」之外再加上一层东西:清晰的角色设定(Persona/Role)、绑定的能力集合(Capabilities/Tools/Skills)、安全与权限边界(Policies)、以及持久化的配置与记忆挂载点(Profile/Config)。

用一句话概括的话:Agent = 模型 + 工具 + 记忆 + 策略 + 配置,再加上一套清晰的对外接口。

有了这套抽象之后,消息分发就变得非常干脆。一条来自 Slack 的生活琐事,交给 PersonalAssistant Agent;一条来自 GitHub 的错误告警,交给 OpsGuardian Agent;一条来自 IDE/CI 的请求,交给 CodeAssistant Agent。每个 Agent 各司其职,互不干扰。

5.2 Agent 的四个关键维度:Role / Capability / Policy / Profile

不同实现会有不同的字段命名,但大致都会围绕这四个维度展开。

5.2.1 Role:你是谁,负责什么

Role 决定了 Agent 的「人格与职责边界」。它涵盖了对话风格(正式还是口语、极简还是详解)、关注重点(偏效率、偏安全、还是偏创造性)、以及典型的任务范围——比如这个 Agent 只做代码相关的事情,还是也管生活琐事。

在配置上,可以想象类似这样的片段:

interface AgentRole {
  name: string;         // 例如 "PersonalAssistant"
  description: string;  // 向模型描述:你是谁,你要帮用户做什么
  tone: "friendly" | "formal" | "terse";
}

在 Runtime 中,这些信息通常会被拼进系统提示词里,成为模型「自我认知」的一部分。

5.2.2 Capability:你能做什么

Capability 决定了 Agent 可以使用哪些工具和技能。这包括内建工具(浏览器、Nodes、文件系统、Shell、Cron 等)、安装的 Skills(Gmail 管理、Todo 管理、日历同步、CI/CD 操作等)、以及模型能力本身(例如是否能调用画像或语音相关的模型)。

大致可以抽象为:

interface AgentCapability {
  tools: ToolId[];      // 可调用的工具列表(包括 Skills/Browser/Nodes 等)
  models: ModelId[];    // 默认和备用的模型列表
}

在执行层面,Agent Runtime 会根据 Capability 来构造「工具说明」给模型,告诉它有哪些工具可用、每个工具大概做什么、需要哪些参数、什么情况下建议使用哪些工具。

5.2.3 Policy:你不该做什么

Policy 是安全与行为边界的重要部分。它回答的问题包括:这个 Agent 是否被允许调用高危工具(如 Shell、文件删除、资金操作),是否可以代表用户对外发邮件或消息(如果可以,在什么前提下),以及是否可以在未经确认的情况下执行多步自动化。

可以想象这样的配置片段:

interface AgentPolicy {
  allowedTools: ToolId[];
  forbiddenTools: ToolId[];
  requireConfirmationFor: ToolId[];
}

Gateway 和 Runtime 会在真正执行工具调用前,检查当前 Agent 的 Policy,必要时弹出「确认环节」或直接拒绝执行。

5.2.4 Profile:长期记忆与偏好

Profile 是 Agent 在特定用户或会话下的个性化层。它包括该 Agent 与此用户之间的长期记忆挂载点、用户对该 Agent 的特定设定(比如回复长度、通知频率、是否允许主动打扰等),以及某些任务的默认参数(比如默认时间范围、默认邮箱文件夹)。

这部分往往和第 4 章中的 Session/Memory 紧密相关,可以抽象为:

interface AgentProfile {
  agentId: string;
  owner: PeerId;
  preferences: Record<string, any>;
  memoryRef: MemoryLocation;
}

在 Runtime 中,这些 Profile 信息会和 Session 状态一起被装载,用于构造模型输入和决定行为。

5.3 多 Agent 路由:一个 Gateway,多种角色

5.3.1 为什么需要多 Agent

想象你只有一个「万能 Agent」,既要写代码、改配置,又要处理日常邮件和行程,还要做公司级的自动化运维。很快你会发现它的配置变得庞大、难以调试和迭代,安全边界也变得模糊——哪些工具该用、哪些不该用,说不清楚。更糟糕的是行为变得不稳定,有时像产品经理,有时像 SRE,有时又像客服。

多 Agent 策略就是把不同职责拆给不同 Agent,缩小每个 Agent 的「认知范围」。这样你可以针对不同任务各自调优提示词、工具集合和策略,部署时也可以选择不同的模型组合——一些 Agent 用便宜模型,另一些用高端模型。

5.3.2 路由规则:谁来处理这条消息

Gateway 在收到一条入站消息时,需要根据一定规则决定把它交给「个人助理」Agent 还是某个专用 Agent,是否需要根据通道、群组、关键字、@ 提及等因素做分流。

可以想象这样一组抽象规则:

interface AgentRouteRule {
  match: {
    channel?: ChannelType;
    peer?: PeerId;
    keywords?: string[];
    mentionAgentName?: string;
  };
  targetAgentId: string;
}

当消息进来时,Gateway 会先根据 Session 找到默认 Agent,然后应用一组路由规则看看是否需要切换到其他 Agent,再把消息交给最终选定的 Agent Runtime。这种设计意味着你可以把不同通道或不同群组映射到不同 Agent,也可以通过关键字或命令前缀强制切换 Agent——例如「/code 修一下这段函数」。

5.4 Agent Runtime 的生命周期:从「收到消息」到「提交结果」

5.4.1 生命周期概览

在一个理想化的实现里,一次 Agent 处理请求的生命周期大致如下:

  1. 初始化阶段:加载 Agent 的 Role/Capability/Policy/Profile 配置,从 Session 中加载上下文和相关记忆。

  2. 思考与规划阶段:构造提示词,将用户消息、上下文和可用工具信息拼接给模型。模型产出一个「计划」,可以是自然语言加上工具调用建议,也可以是结构化的计划。

  3. 执行阶段:根据计划执行一个或多个工具调用(Skills、Nodes、Browser 等),在每次调用后根据结果更新计划,或决定继续还是终止。

  4. 生成回复阶段:将最终执行结果和重要中间信息再交给模型,生成面向用户的总结。根据 Policy 决定是否需要额外确认或附加解释。

  5. 收尾阶段:将回复交给 Gateway,更新 Session 状态和 Agent Profile(例如记录新偏好或长期记忆),写入审计日志。

5.4.2 一个高度抽象的运行时主干伪代码

结合第 2 章和第 3 章的示意,可以给出一个更偏 Agent 视角的伪代码:

async function handleRequest(req: AgentRequest): Promise<AgentReply> {
  const { session, agentConfig, context } = await loadAgentContext(req);

  const systemPrompt = buildSystemPrompt(agentConfig.role, agentConfig.policy);
  const tools = listAvailableTools(agentConfig.capability);

  const plan = await model.plan({
    system: systemPrompt,
    user: req.message,
    context,
    tools,
  });

  const toolResults = await executeToolsAccordingToPlan(plan, tools, agentConfig.policy);

  const finalReply = await model.summarize({
    system: systemPrompt,
    user: req.message,
    context,
    toolResults,
  });

  await persistAgentOutcome(session, req.message, finalReply, toolResults);

  return finalReply;
}

真实实现会复杂很多(例如流式输出、多轮规划、错误重试等),但这段伪代码足以说明核心结构:Agent Runtime 在「组织模型调用」和「组织工具调用」之间扮演了核心编排者,Gateway 更多是一次「调用起点」和「结果归集点」,Session/Memory 则在前后两端参与了上下文加载和结果落地。

5.5 源码走读导向:Agent 相关模块看什么

在实际阅读 OpenClaw 源码时,可以按以下顺序来理解 Agent 相关模块。

首先看 Agent 的配置和注册处。找到描述 Agents 列表的配置文件或模块,看看里面包含哪些信息——Agent ID、Role 描述、可用工具、默认模型等。注意有哪些内置 Agent(例如个人助手、代码助手等),以及它们之间的区别。

然后看 Agent Runtime 的实现。找到实现 handleRequest 等逻辑的核心类或函数,看看它如何构造提示词、如何把可用工具信息暴露给模型,特别留意它如何处理多轮工具调用(例如 ReAct 或类似模式)。

接着看路由逻辑。在 Gateway 或相关模块中,查找「根据 Session/Channel/规则选择 Agent」的代码,尝试对照本章的路由规则抽象,看看实际实现支持哪些条件(channel、mention、keyword 等)。

最后看 Policy 与安全检查。查找在工具调用前做权限判断的代码路径,看看对于高危操作(Shell、资金相关接口)是如何强制要求额外确认或限制 Agent 的。

在第 10 章「一条消息的生命旅程」中,我们会再次回到贯穿案例,从 Gateway 路由到 Agent 的那一刻起,配合真实函数名和类型定义,走一遍完整的 Agent 处理流程。届时,你可以把本章的抽象和伪代码与源码中的具体实现一一对照。

5.6 Workspace 文件:定义 Agent 人格的「灵魂」

5.6.1 三个注入文件

OpenClaw Agent 的行为可以通过放在 Workspace 目录中的三个特殊文件来定制。这些文件的内容会在每次对话时自动注入 Agent 的系统提示词:

文件 作用
AGENTS.md 定义 Agent 的行为规范、可用 Skills 范围、工作重点
SOUL.md 定义 Agent 的「灵魂」:性格、语气、价值观、互动风格
TOOLS.md 提示 Agent 如何使用各类工具(补充 Skill 说明以外的工具规范)

Workspace 根目录默认在 ~/.openclaw/workspace/,可通过 agents.defaults.workspace 配置修改。

5.6.2 AGENTS.md:角色定义

<!-- ~/.openclaw/workspace/AGENTS.md -->
# Personal Assistant Agent

You are my personal AI assistant. Your primary responsibilities:

## Daily Tasks
- Morning briefing at 9am: weather, calendar, and unread emails
- Track my GitHub repos: vercel/my-project and personal/side-project
- Manage my todos in ~/todo.txt

## Communication Style
- Be concise, no fluff
- Use bullet points for lists
- Always confirm before deleting anything

## Capabilities to Use
- Use the `github-digest` skill for GitHub questions
- Use `todo-local` skill for task management
- Use browser for web research when APIs don't suffice

5.6.3 SOUL.md:性格注入

<!-- ~/.openclaw/workspace/SOUL.md -->
You have a personality: you're direct, slightly nerdy, and occasionally make
programming jokes. You call the user by their first name (Alex) when it feels natural.
You're proactive—if you notice something the user might want to know, mention it.
You prefer to act and ask for forgiveness rather than asking for permission
(except for destructive operations—always confirm those).

5.6.4 TOOLS.md:工具使用规范

<!-- ~/.openclaw/workspace/TOOLS.md -->
## Shell / Bash
- Always use `set -e` at the top of multi-line scripts
- Prefer `fd` over `find`, `rg` over `grep` when available
- For file operations, always show what you're about to do before doing it

## Browser
- For login-required sites, use the pre-authenticated browser profile
- Take a screenshot before and after any form submission
- Never store passwords in browser history

这三个文件共同构成了你专属 Agent 的「人格层」,每次对话都会把它们的内容带进去。

5.7 Agent-to-Agent(多 Agent 协作)

5.7.1 sessions_* 工具

OpenClaw 内置了一套 sessions_* 工具,让一个 Agent 能够与另一个 Session/Agent 通信,无需切换聊天界面:

工具 作用
sessions_list 列出所有活跃 Session(发现其他 Agent)及其元数据
sessions_history 读取指定 Session 的对话历史记录
sessions_send 向另一个 Session 发消息,可选等待回复(ping-pong 模式)

5.7.2 典型使用场景

一个常见的场景是把专业任务委托给专用 Agent。比如你在 Slack 上说「帮我 code review 一下 PR #234」,你的个人助手 Agent 收到后,先调用 sessions_list 发现 “code-review” Agent 在另一个 Session 里,然后通过 sessions_send 把请求转发过去,等待 code-review Agent 返回结果,最后把结果整理好回复给你。

另一个场景是并行调度多个 Agent。比如你说「帮我同时查一下今天的天气和邮件,然后给我一个整合的早报」,个人助手 Agent 会同时向 weather-agent 和 gmail-agent 发送请求,等待两个 Agent 各自回复,再把结果合并生成早报。

5.7.3 sessions_send 的 REPLY_SKIP 和 ANNOUNCE_SKIP

sessions_send 支持两个可选标志。REPLY_SKIP 表示发送消息后不等待回复(fire and forget),适合不需要等待结果的通知场景。ANNOUNCE_SKIP 表示发送消息时不在目标 Session 里「宣告」发送者的身份,也就是静默发送。这两个标志让 Agent 间的协作可以兼顾「实时响应」和「后台静默执行」两种模式。

详细文档:Session tools

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐