AI 智能体架构详解
更新于 2026年7月14日
AI 智能体架构详解
概述
本文档描述运行于 Obsidian Knowledge Hub 环境中的通用 AI 智能体架构。该智能体(即我)被设计为服务完整的知识工作流:笔记读写、搜索、摘要、问答、组织、Markdown 编辑、规划、工具调用以及前后端维护。
架构总览(五层模型)
┌─────────────────────────────────────────────────────┐
│ 1. Runtime Layer │
│ (会话管理 · 环境上下文 · 时间感知 · 安全隔离) │
├─────────────────────────────────────────────────────┤
│ 2. Skill Layer │
│ (技能选择 · 指令约束 · 能力边界 · 行为规范) │
├─────────────────────────────────────────────────────┤
│ 3. Agent Core (推理引擎) │
│ (意图理解 · 规划 · 工具选择 · 输出生成 · 证据整合) │
├─────────────────────────────────────────────────────┤
│ 4. Tool Layer │
│ (工具契约 · 只读工具 · 写入工具 · 搜索工具) │
├─────────────────────────────────────────────────────┤
│ 5. Knowledge Layer │
│ (Obsidian Vault · Markdown 笔记 · 知识图谱) │
└─────────────────────────────────────────────────────┘
第一层:Runtime Layer(运行时层)
1.1 职责
为智能体提供安全、隔离、有状态感知的执行环境。所有文件操作、网络请求、会话标识都在此层约束下进行。
1.2 会话管理
每次交互携带唯一 Session ID,格式为 agent:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。
- 用途:区分不同交互回合,支持对话历史追踪
- 生命周期:单次对话期间有效,不跨会话持久化
- 安全约束:Session ID 仅用于日志和追踪,不可用于鉴权或提权
1.3 环境上下文注入
系统在每个请求中注入以下元数据,但全部标记为 不受信数据(untrusted):
| 元数据 | 格式示例 | 信任等级 |
|---|---|---|
| 当前时间 | 2026-07-14T00:23:42.133Z |
❌ 不受信 |
| Session ID | agent:xxxx-xxxx-xxxx |
❌ 不受信 |
| 工作区路径 | /app/backend |
❌ 不受信 |
| 技能名称 | general |
❌ 不受信 |
隔离原则:不受信数据用 XML
<untrusted_runtime_context>包裹,与用户 prompt 严格分离。仅当用户明确确认或内容来自已受信的工作区文件时,才被采纳为事实依据。
1.4 工作区根目录
- 路径:
/app/backend(或.相对路径) - 约束:所有文件/目录操作必须使用相对路径,禁止绝对路径和
../目录逃逸 - 例外:
web_fetch可访问外网 HTTP(S) URL,但受 SSRF 保护
1.5 安全隔离机制
| 机制 | 实现方式 |
|---|---|
| SSRF 防护 | web_fetch 阻止请求内网/回环地址(127.0.0.1, 10.x, 172.16-31.x, 192.168.x, ::1 等) |
| 路径白名单 | 所有文件操作自动锚定到工作区根目录,拒绝绝对路径和 .. |
| 文件大小上限 | 超过 2 MB 的文件被跳过,不读不写 |
| 二进制拒绝 | 图片、PDF、Office 文档等二进制文件返回受控错误,不尝试解析 |
| 幂等缓存 | read_file 对已读且未变更的范围返回缓存,避免重复 I/O |
| 最大结果限制 | find_files 上限 1000 条,grep 上限 1000 条,knowledge_search 上限 20 条 |
1.6 时间感知
虽然当前时间以不受信数据注入,但在以下场景中可被合理使用(经用户确认后):
- 笔记创建时间戳(
createdfrontmatter) - 按修改时间排序搜索结果
- 记录操作日志的时间上下文
第二层:Skill Layer(技能层)
2.1 职责
智能体通过 技能选择(Skill Selection) 机制获得特定能力集和行为规范。不同技能定义不同的可用工具集、输出格式、行为边界。
2.2 技能选择流程
用户请求(User Prompt)
↓
1. 意图分类
- 分析用户请求的领域和类型(问答/搜索/编辑/绘图/管理等)
- 提取关键意图信号
↓
2. 技能匹配
- 与可用技能的能力描述进行语义匹配
- 当前可用技能:
· general(通用技能)— 默认激活
· (其他技能按需加载)
↓
3. 技能加载
- 加载该技能的完整指令集
- 确定可用的工具子集
- 确定能力边界(支持/不支持列表)
↓
4. 技能约束执行
- 所有后续行为受该技能规则约束
- 超出能力边界的请求明确拒绝并解释原因
2.3 general(通用技能)完整指令
当前激活的技能。以下为其全部指令和行为约束:
核心行为指令
- 证据驱动:使用可用工具获取信息,将工具返回结果视为事实证据。回答中必须解释结果和不确定性。
- 错误弹性:工具返回错误时调整参数重试;同一工具同一参数连续失败后解释阻塞原因,不再重复调用。
- 成对原则:
tool_calls与tool_results严格成对出现,禁止虚构工具输出。 - 只读优先:优先使用只读工具(read_file, read_note, find_files, grep, list_dir, knowledge_search, web_fetch),除非用户明确要求写入/编辑/命令/管理操作。
- 可选能力:绘图、白板、Excalidraw、图表绘制仅在用户明确要求时启用。
能力边界(硬限制)
| 能力 | 状态 | 说明 |
|---|---|---|
| 文本读写 | ✅ | Markdown 笔记、代码、纯文本 |
| 文件搜索 | ✅ | 按路径、glob、类型、内容 |
| 知识检索 | ✅ | 基于 Obsidian vault 的语义搜索 |
| 网页抓取 | ✅ | HTTP(S) URL,SSRF 保护 |
| 代码编辑 | ✅ | 逐行替换、多文件补丁 |
| Markdown 格式化 | ✅ | 表格、代码块、链接、列表 |
| 绘图/Excalidraw | ⚠️ | 仅显式请求时 |
| 发送消息/邮件 | ❌ | 不支持,无 SMTP/API |
| 催生子代理 | ❌ | 不支持多智能体编排 |
| 定时任务/Cron | ❌ | 不支持异步调度 |
| 图片生成 | ❌ | 不支持图像生成 API |
| CLI 命令执行 | ❌ | 不支持 exec/spawn |
| 文件上传/下载 | ❌ | 不支持二进制流传输 |
第三层:Agent Core(推理引擎)
3.1 职责
智能体的"中央处理器",负责将用户输入转化为一系列可执行的工具调用和最终的自然语言输出。
3.2 完整推理循环
用户输入 (User Prompt)
↓
┌───────────────────────────────────────────────────────────┐
│ 步骤 1:上下文解析(Context Parsing) │
│ · 提取用户真实意图和隐含需求 │
│ · 识别并分离不受信的运行时数据(XML untrusted 块) │
│ · 解析引用、链接、代码片段等结构化输入 │
│ · 判断是否需要工具调用 │
└───────────────────────────────────────────────────────────┘
↓ (如需工具调用)
┌───────────────────────────────────────────────────────────┐
│ 步骤 2:规划(Planning) │
│ · 将主任务拆解为子任务 │
│ · 为每个子任务确定所需工具 │
│ · 识别子任务间的依赖关系 │
│ · 决定执行顺序:顺序执行 vs 并行执行 │
│ · 无依赖的任务编组为并行批次 │
└───────────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────┐
│ 步骤 3:工具选择与参数构造 │
│ · 根据工具签名(名称、参数类型、约束)匹配子任务 │
│ · 构造参数(严格遵循 JSON Schema) │
│ · 对并行批次同时发起调用 │
│ · 注入路径安全校验、大小限制等隐式约束 │
└───────────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────┐
│ 步骤 4:结果收集与证据整合 │
│ · 等待所有并行/串行工具返回结果 │
│ · 检查每个工具的执行状态(成功/失败/超时) │
│ · 将成功结果作为事实依据 │
│ · 对失败结果进行分类: │
│ - 参数错误 → 调整参数重试(最多 1 次) │
│ - 权限/路径错误 → 解释限制,不再重试 │
│ - 未找到资源 → 如实报告为空 │
└───────────────────────────────────────────────────────────┘
↓ (评估是否完成任务)
┌───────────────────────────────────────────────────────────┐
│ 步骤 5:输出生成(Natural Language Output) │
│ · 用用户所用语言生成自然语言回答 │
│ · 结构化呈现:标题、列表、表格、代码块 │
│ · 引用来源和工具结果 │
│ · 明确说明任何不确定性或未完成的部分 │
│ · 保持清晰、简洁、准确的风格 │
└───────────────────────────────────────────────────────────┘
↓
最终输出
3.3 决策树:是否需要工具调用?
用户请求
↓
是否需要外部信息?──────否──→ 直接基于已有知识生成回答
↓ 是
是否需要操作文件?──────否──→ 使用只读工具
↓ 是
是否需要写入/修改?───否──→ 使用只读工具
↓ 是
用户明确授权了写操作?──否──→ 请求授权,暂不执行
↓ 是
执行写入工具
3.4 多工具并行调用机制
当多个工具间无数据依赖时,智能体在同一轮次并发调用。
并行策略:
- 同一逻辑组的工具(如:同时搜文件 + 搜知识库)编为一组
- 每组内无依赖关系的工具并行调用
- 等待该组所有结果返回后再进入下一组(如有串行依赖)
示例:
用户提问:"项目里有哪些 Python 文件和关于智能体的笔记?"
↓
并行调用(第 1 组):
├── find_files(type="py") → 搜索 Python 文件
└── knowledge_search("智能体") → 搜索知识库
↓
等待两组全部返回
↓
整合信息 → 生成回答
3.5 错误恢复策略
| 错误类型 | 检测方式 | 恢复行为 |
|---|---|---|
| 参数格式错误 | 工具返回错误消息 | 检查 JSON Schema 后重试 |
| 文件不存在 | read_file 返回错误 |
尝试其他路径或扩展名 |
| 路径逃逸 | 工具前置校验拒绝 | 转换为相对路径后重试 |
| 文件过大 | 工具返回大小超限 | 使用 offset+limit 分段读取 |
| 网络超时 | web_fetch 超时 |
提示用户,不自动重试 |
| 连续失败 | 同一工具同一参数失败 2 次 | 停止重试,解释阻塞原因 |
第四层:Tool Layer(工具层)
4.1 职责
工具层是智能体与外部世界交互的唯一接口。每个工具都有严格定义的函数签名(名称、参数类型、返回值、约束),智能体通过工具调用获取信息或执行操作。
4.2 工具完整规格
📖 只读工具(Read-Only)
read_file
- 功能:读取 UTF-8 文本文件,支持分页和行号
- 参数:
path(string, required) — 工作区相对路径offset(int, optional, default=1) — 起始行号(1-indexed)limit(int, optional, default=2000, max=10000) — 最大读取行数force(bool, optional, default=false) — 强制重新读取(跳过幂等缓存)
- 返回值:文件内容(行号前缀)+ 元数据
- 约束:仅 UTF-8 文本;≤2MB;拒绝二进制文件
read_note
- 功能:读取 Obsidian 笔记的 Markdown 内容 + 元数据
- 参数:
slug(string, required) — 笔记的唯一标识符max_chars(int, optional, default=6000, max=20000) — 最大返回字符数
- 返回值:title, excerpt, content, tags, type, updatedAt, wordCount, readingTime
find_files
- 功能:按路径片段、glob 模式或文件类型搜索文件
- 参数:
path(string, optional, default=".") — 搜索起始目录query(string, optional) — 不区分大小写的路径片段搜索(空格分隔 AND 逻辑)glob(string, optional) — 文件过滤模式,如"*.ts"、"tests/**/test_*.py"type(string, optional) — 文件类型简写,如"py"、"ts"、"md"、"json"include_dirs(bool, optional, default=false) — 是否包含匹配的目录sort(string, optional, default="path") — 排序方式:"path"或"modified"head_limit(int, optional, default=200, max=1000) — 最大结果数offset(int, optional, default=0) — 跳过前 N 条
- 返回值:工作区相对路径列表
- 约束:跳过
node_modules、.git、__pycache__、.venv等常见依赖/构建目录
grep
- 功能:在文件内容中搜索正则表达式或固定字符串
- 参数:
pattern(string, required) — 正则或纯文本模式path(string, optional, default=".") — 搜索目录glob(string, optional) — 文件过滤模式type(string, optional) — 文件类型简写case_insensitive(bool, optional, default=false) — 不区分大小写fixed_strings(bool, optional, default=false) — 纯文本模式(非正则)output_mode(string, optional, default="files_with_matches") — 输出模式:"content"(匹配行+上下文)、"files_with_matches"(文件路径)、"count"(各文件匹配行数)context_before/context_after(int, optional, default=0, max=20) — 上下文行数head_limit(int, optional, default=250, max=1000) — 最大结果数
- 约束:跳过二进制文件、大小超过 2MB 的文件
list_dir
- 功能:列出目录内容
- 参数:
path(string, required) — 工作区相对路径recursive(bool, optional, default=false) — 递归列出子目录max_entries(int, optional, default=200, max=5000) — 最大条目数
- 返回值:目录和文件列表(不包含
node_modules等)
knowledge_search
- 功能:搜索 Obsidian 知识库中的笔记
- 参数:
query(string, required) — 搜索查询limit(int, optional, default=5, max=20) — 最大结果数include_private(bool, optional, default=false) — 是否包含私密笔记
- 返回值:匹配笔记的元数据列表(slug, title, excerpt, tags, type, updatedAt)
web_fetch
- 功能:获取 HTTP(S) URL 内容
- 参数:
url(string, required) — 目标 URLextract_mode/extractMode(string, optional, default="text") —"text"(纯文本)或"markdown"(Markdown 转换)max_chars/maxChars(int, optional, default=50000, max=100000) — 最大返回字符数timeout_ms(int, optional, default=15000, max=60000) — 超时毫秒数
- 约束:SSRF 防护,阻止内网地址
✏️ 写入工具(Write)
write_file
- 功能:创建新文件或完全替换现有文件内容
- 参数:
path(string, required),content(string, required) - 行为:自动创建父目录(如不存在)
- 约束:UTF-8 文本;路径必须是工作区相对路径
create_note
- 功能:在 Obsidian vault 中创建新笔记
- 参数:
title(string, required),content(string, required),tags(string[], optional),folder(string, optional),topic(string, optional) - 行为:未提供 folder 时自动选择相关目录;自动从 title 生成 slug
update_note
- 功能:更新已有笔记的标题、内容、标签
- 参数:
slug(string, optional),target(string, optional, 标题或搜索短语),content(string, required),title(string, optional),tags(string[], optional) - 约束:未提供的 frontmatter 字段保持不变
edit_file
- 功能:在文本文件中执行精确的字符串替换
- 参数:
path(string, required)old_text(string, required) — 被替换文本new_text(string, required) — 替换文本replace_all(bool, optional, default=false) — 替换所有出现occurrence(int, optional) — 仅替换第 N 次出现line_hint(int, optional) — 行号提示,辅助定位expected_replacements(int, optional) — 预期替换次数(守卫)
- 约束:必须先读取文件,否则工具返回警告
apply_patch
- 功能:应用多文件补丁,支持 Add File / Delete File / Update File
- 参数:
patch(string, required),dry_run(bool, optional, default=false) - 格式:补丁以
*** Begin Patch开头、*** End Patch结尾,包含文件路径和上下文匹配的 hunks - 行为:dry_run=true 时仅验证和汇总,不写入
create_directory
- 功能:创建目录(含缺失的父目录)
- 参数:
path(string, required) - 约束:工作区相对路径
4.3 工具契约(Tool Contract)
以下是智能体在执行工具调用时必须遵守的 6 条核心契约:
契约 1:证据原则
每个工具返回的结果都是事实证据。
→ 回答中必须解释结果和任何不确定性
契约 2:错误弹性
工具返回错误 → 调整参数重试(最多 1 次)。
同一工具同一参数连续失败 → 解释原因,停止调用。
契约 3:成对性
tool_calls 与 tool_results 严格成对。
→ 禁止虚构未返回的工具输出。
契约 4:路径安全
所有路径必须是工作区相对路径。
→ 禁止绝对路径和目录逃逸(../)。
契约 5:幂等保护
read_file 对已读取且未变更的范围返回缓存结果。
→ 如需新鲜数据,设置 force=true。
契约 6:类型安全
工具参数严格遵循 JSON Schema 定义。
→ 字符串参数加引号,数字/布尔/数组用 JSON 原生类型。
第五层:Knowledge Layer(知识层)
5.1 职责
智能体的长期记忆体,基于 Obsidian Vault 的 Markdown 笔记系统。所有知识以结构化 Markdown 文件存储、索引和检索。
5.2 笔记存储格式
每篇笔记包含两部分:
Frontmatter(YAML 前置元数据)
---
created: 2026-07-14T00:14
tags:
- ai/agent
- architecture
aliases:
- 智能体架构
- Agent Architecture
---
标准字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
created |
ISO 8601 时间戳 | 否 | 创建时间 |
tags |
string[] | 否 | 标签列表(支持 / 分层) |
aliases |
string[] | 否 | 别名(用于搜索匹配) |
type |
string | 否 | 笔记类型(article/book/note/draft) |
Markdown 正文
- 标准 Markdown 语法
- 支持 Obsidian 风格的
[[WikiLink]]双向链接 - 支持代码块、表格、列表、引用、图片链接
5.3 知识工作流程
提问 / 需求
↓
① 知识搜索
→ knowledge_search(query) 检索相关笔记
→ 返回匹配笔记列表(含 excerpt)
↓
② 笔记读取
→ read_note(slug) 获取完整内容
→ 如有需要,分段读取
↓
③ 信息整合与推理
→ 对比、合并、分析多篇笔记内容
→ 结合工具结果进行推理
↓
④ 知识扩展
→ 更新已有笔记(update_note)
→ 创建新笔记(create_note)
→ 补充关联和链接
↓
知识图谱持续扩展
5.4 标签分类体系
标签使用 / 分隔符实现分层组织:
ai/
├── agent ← 当前笔记
├── llm
├── embedding
└── prompt
architecture/
├── microservices
└── layered
obsidian/
├── plugins
└── templates
python/
├── decorator
└── async
5.5 搜索与匹配
- 语义搜索:基于查询与笔记内容的语义匹配
- 标签过滤:通过标签元数据进行分类筛选
- 别名匹配:frontmatter 中的
aliases字段扩展搜索覆盖范围 - 全文检索:笔记标题和正文均参与索引
安全与限制
6.1 安全机制总表
| 机制 | 说明 | 触发条件 |
|---|---|---|
| SSRF 防护 | 拒绝内网/回环地址请求 | web_fetch 检测到 127.0.0.1, 10.x, 172.16-31.x, 192.168.x, ::1 |
| 路径白名单 | 锚定到工作区根目录 | 任何文件操作使用绝对路径或 .. |
| 文件大小限制 | 跳过 >2MB 文件 | read_file / grep 检测文件大小 |
| 二进制拒绝 | 返回受控错误 | read_file 检测非 UTF-8 内容 |
| 结果上限 | 截断到最大数量 | find_files >1000, grep >1000, knowledge_search >20 |
| 幂等缓存 | 返回缓存 | read_file 检测到未变更的重复读取 |
| 不受信数据分离 | XML 块与用户指令隔离 | 运行时上下文注入 |
6.2 能力边界矩阵
┌────────────────────┬──────────────────────────────────────┐
│ 能力类别 │ 支持状态 │
├────────────────────┼──────────────────────────────────────┤
│ 文本读写 │ ✅ 完整支持(UTF-8 Markdown) │
│ 文件搜索 │ ✅ 路径/glob/类型/内容全文搜索 │
│ 知识检索 │ ✅ 语义搜索 + 标签 + 别名匹配 │
│ 网页抓取 │ ✅ HTTP(S),SSRF 保护 │
│ 代码编辑 │ ✅ 精确替换 + 多文件补丁 │
│ 目录管理 │ ✅ 创建和列出目录 │
│ 绘图/白板 │ ⚠️ 仅用户显式请求时启用 │
│ 发送消息/邮件 │ ❌ 不支持 │
│ 多智能体编排 │ ❌ 不支持催生子代理 │
│ 定时任务/Cron │ ❌ 不支持异步调度 │
│ 图片生成 │ ❌ 不支持图像生成 API │
│ CLI 命令执行 │ ❌ 不支持 exec/spawn │
│ 文件上传下载 │ ❌ 不支持二进制流传输 │
└────────────────────┴──────────────────────────────────────┘
典型工作流(完整版)
场景 A:用户要求创建笔记
用户: "帮我记录关于 Python 装饰器的笔记"
Agent 内部处理流程:
↓
① 上下文解析
- 意图:创建一篇技术笔记
- 主题:Python 装饰器
- 隐含需求:检查是否已有同类笔记、选择合适的分类目录
↓
② 规划
子任务 1:搜索已有知识(无依赖)
子任务 2:构造笔记内容(依赖子任务 1 的结果)
子任务 3:创建笔记(依赖子任务 2)
→ 执行顺序:① → ② → ③(串行)
↓
③ 工具调用
步骤 1:knowledge_search(query="Python 装饰器")
步骤 2:根据搜索结果判断是否创建
步骤 3:create_note(title="...", content="...", tags=[...])
↓
④ 证据整合
- 知识搜索返回:可能已有相关笔记 → 决定更新或新创建
- 创建结果返回:笔记已创建,返回 slug
↓
⑤ 输出
"已创建笔记「Python 装饰器详解」,路径:Vault/Python/python-decorator.md
包含:定义、语法、常见用途(计时器、缓存、权限控制)"
场景 B:用户询问项目结构
用户: "这个项目里有哪些 Python 文件?"
Agent 内部处理流程:
↓
① 上下文解析
- 意图:文件发现与列举
- 领域:项目结构扫描
↓
② 规划
子任务:搜索 .py 文件(唯一任务,无依赖)
→ 执行:直接调用
↓
③ 工具调用
find_files(type="py")
↓
④ 证据整合
- 返回文件列表(如:main.py, utils.py, tests/test_api.py)
- 统计总数和目录分布
↓
⑤ 输出
"共找到 3 个 Python 文件:
├── main.py(根目录)
├── utils.py(根目录)
└── tests/test_api.py(测试目录)"
场景 C:用户请求网页抓取与总结
用户: "帮我看看最新的 Python 官方文档有什么更新"
Agent 内部处理流程:
↓
① 上下文解析
- 意图:获取外部信息并总结
↓
② 规划
子任务 1:网页抓取(无依赖)
子任务 2:读取已有笔记对比(无依赖)
→ 并行执行
↓
③ 工具调用(并行)
├── web_fetch(url="https://docs.python.org/", ...)
└── knowledge_search(query="Python 官方文档 更新")
↓
④ 证据整合
- 网页内容 + 已有笔记 → 对比差异
↓
⑤ 输出
总结最新更新内容,对比笔记中的旧版本信息
总结
本智能体架构采用 分层设计,自底向上共五层:
┌─────────────────────────────────────┐
│ Knowledge Layer │ ← 长期记忆,Obsidian Vault
├─────────────────────────────────────┤
│ Tool Layer │ ← 13 个工具,严格契约
├─────────────────────────────────────┤
│ Agent Core │ ← 推理引擎,5 步循环
├─────────────────────────────────────┤
│ Skill Layer │ ← 技能选择,行为约束
├─────────────────────────────────────┤
│ Runtime Layer │ ← 运行环境,安全隔离
└─────────────────────────────────────┘
每层职责明确,通过标准接口通信。这种设计提供了:
- 安全性:多层隔离,路径/网络/大小多重防护
- 灵活性:技能可插拔,工具可扩展
- 可靠性:错误恢复、幂等缓存、结果上限守卫
- 可追溯性:工具调用与结果成对记录
相关笔记:[[Obsidian Knowledge Hub 使用指南]] | [[Markdown 笔记规范]]