Files
beaver_project/app-instance/backend/docs/architecture/backend-visualization.html
steven_li 9d6cde2d23 feat: 将项目从nano重命名为beaver并更新相关配置
- 将所有环境变量前缀从NANO_改为BEAVER_
- 更新README.md文档内容,包括项目介绍、组件说明和快速开始指南
- 修改.gitignore文件,添加auth-portal运行时路径排除规则
- 更新app-instance镜像标签从nano/app-instance改为beaver/app-instance
- 增强技能安全检查器,支持工具前缀白名单功能
- 添加技能草稿重新检查安全性API端点
- 扩展证据选择器,收集工具调用名称用于技能学习
- 改进技能合成器,基于实际调用的工具生成工具提示
- 优化路由超时处理机制,增加重试逻辑
- 更新后端架构文档,添加可视化入口和基础概念说明
- 实现在WebSocket消息中传递工具迭代次数信息
2026-05-20 18:01:06 +08:00

1389 lines
62 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Beaver Backend Visualization</title>
<style>
:root {
color-scheme: light;
--bg: #f7f8fb;
--ink: #172033;
--muted: #5d6b82;
--line: #d7deea;
--panel: #ffffff;
--blue: #2563eb;
--green: #0f8b6f;
--amber: #b7791f;
--rose: #be4266;
--violet: #6953c6;
--cyan: #147d96;
--shadow: 0 14px 36px rgba(23, 32, 51, 0.08);
--radius: 8px;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.45;
}
button {
font: inherit;
}
.page {
width: min(1440px, 100%);
margin: 0 auto;
padding: 28px 28px 40px;
}
.topbar {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
margin-bottom: 20px;
}
h1 {
margin: 0 0 8px;
font-size: 30px;
line-height: 1.14;
letter-spacing: 0;
}
.subtitle {
margin: 0;
max-width: 760px;
color: var(--muted);
font-size: 15px;
}
.meta {
display: grid;
grid-template-columns: repeat(3, max-content);
gap: 8px;
align-items: center;
color: var(--muted);
font-size: 12px;
white-space: nowrap;
}
.pill,
.pill-link {
border: 1px solid var(--line);
background: var(--panel);
border-radius: 999px;
padding: 6px 10px;
}
.pill-link {
color: var(--ink);
text-decoration: none;
display: inline-flex;
align-items: center;
}
.layout {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 16px;
align-items: start;
}
.canvas {
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
overflow: hidden;
}
.tabs {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding: 14px;
border-bottom: 1px solid var(--line);
background: #fbfcff;
}
.tab {
border: 1px solid var(--line);
border-radius: 999px;
background: #fff;
color: var(--ink);
min-height: 34px;
padding: 7px 12px;
cursor: pointer;
}
.tab[aria-selected="true"] {
color: #fff;
border-color: var(--blue);
background: var(--blue);
}
.stage {
display: none;
padding: 22px;
}
.stage.active {
display: block;
}
.stage-title {
display: flex;
justify-content: space-between;
gap: 16px;
align-items: flex-start;
margin-bottom: 16px;
}
h2 {
margin: 0;
font-size: 20px;
letter-spacing: 0;
}
.hint {
margin: 4px 0 0;
color: var(--muted);
font-size: 13px;
}
.legend {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
color: var(--muted);
font-size: 12px;
}
.dot {
width: 10px;
height: 10px;
border-radius: 999px;
display: inline-block;
margin-right: 5px;
vertical-align: -1px;
}
.architecture-grid {
display: grid;
grid-template-columns: 1.1fr 1.2fr 1fr 1fr;
gap: 14px;
align-items: stretch;
}
.lane {
border: 1px solid var(--line);
border-radius: var(--radius);
background: #fbfcff;
min-height: 590px;
padding: 12px;
}
.lane h3 {
margin: 0 0 10px;
font-size: 14px;
color: #374151;
letter-spacing: 0;
}
.node {
position: relative;
width: 100%;
border: 1px solid var(--line);
background: #fff;
border-left: 5px solid var(--blue);
border-radius: var(--radius);
padding: 11px 12px;
margin: 10px 0;
text-align: left;
color: var(--ink);
cursor: pointer;
transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.node:hover,
.node:focus-visible,
.node.selected {
outline: none;
border-color: #9bb7f7;
box-shadow: 0 10px 24px rgba(37, 99, 235, 0.12);
transform: translateY(-1px);
}
.node[data-kind="service"] { border-left-color: var(--blue); }
.node[data-kind="engine"] { border-left-color: var(--green); }
.node[data-kind="capability"] { border-left-color: var(--violet); }
.node[data-kind="interface"] { border-left-color: var(--cyan); }
.node[data-kind="store"] { border-left-color: var(--amber); }
.node[data-kind="governance"] { border-left-color: var(--rose); }
.node strong {
display: block;
font-size: 14px;
line-height: 1.25;
margin-bottom: 4px;
}
.node span {
display: block;
color: var(--muted);
font-size: 12px;
}
.connector {
display: grid;
place-items: center;
height: 22px;
color: #8793a8;
font-size: 18px;
user-select: none;
}
.flow {
display: grid;
gap: 10px;
}
.diagram {
border: 1px solid var(--line);
border-radius: var(--radius);
background: #fbfcff;
padding: 14px;
margin: 0 0 16px;
}
.diagram-title {
margin: 0 0 12px;
font-size: 14px;
color: #374151;
}
.diagram-row {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
align-items: stretch;
}
.diagram-row.four {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.diagram-row.six {
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.diagram-card {
position: relative;
border: 1px solid #dfe6f2;
border-radius: var(--radius);
background: #fff;
padding: 12px;
min-height: 92px;
}
.diagram-card:not(:last-child)::after {
content: "→";
position: absolute;
right: -10px;
top: 50%;
transform: translate(50%, -50%);
width: 22px;
height: 22px;
display: grid;
place-items: center;
border: 1px solid var(--line);
border-radius: 999px;
background: #fff;
color: var(--muted);
font-size: 14px;
z-index: 1;
}
.diagram-card strong {
display: block;
margin-bottom: 5px;
font-size: 13px;
color: var(--ink);
}
.diagram-card span {
display: block;
color: var(--muted);
font-size: 12px;
}
.demo {
border: 1px solid #dfe6f2;
border-radius: var(--radius);
background: #fff;
padding: 14px;
margin-top: 16px;
}
.demo h3 {
margin: 0 0 8px;
font-size: 15px;
}
.demo p {
margin: 0 0 12px;
color: var(--muted);
font-size: 13px;
}
.demo-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.demo-block {
min-width: 0;
}
.demo-block h4 {
margin: 0 0 6px;
font-size: 12px;
color: #374151;
}
.demo pre {
margin: 0;
min-height: 160px;
overflow: auto;
border: 1px solid #e5ebf5;
border-radius: 6px;
background: #f7f9fc;
color: #24324b;
padding: 10px;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 12px;
line-height: 1.45;
white-space: pre-wrap;
}
.primer-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.primer-card,
.glossary-card {
border: 1px solid var(--line);
border-radius: var(--radius);
background: #fff;
padding: 14px;
}
.primer-card h3,
.glossary-card h3 {
margin: 0 0 8px;
font-size: 15px;
}
.primer-card p,
.glossary-card p {
margin: 0;
color: var(--muted);
font-size: 13px;
}
.plain-flow {
display: grid;
gap: 8px;
margin-top: 14px;
}
.plain-step {
display: grid;
grid-template-columns: 92px minmax(0, 1fr);
gap: 12px;
align-items: start;
border: 1px solid #e3e9f4;
border-radius: var(--radius);
background: #fbfcff;
padding: 12px;
}
.plain-step strong {
color: var(--blue);
font-size: 13px;
}
.plain-step p {
margin: 0;
color: var(--muted);
font-size: 13px;
}
.glossary-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
margin-top: 14px;
}
.step {
display: grid;
grid-template-columns: 40px minmax(0, 1fr);
gap: 12px;
align-items: start;
border: 1px solid var(--line);
border-radius: var(--radius);
background: #fff;
padding: 12px;
}
.num {
width: 34px;
height: 34px;
display: grid;
place-items: center;
border-radius: 50%;
color: #fff;
background: var(--blue);
font-weight: 700;
font-size: 14px;
}
.step h3 {
margin: 0 0 4px;
font-size: 15px;
}
.step p {
margin: 0;
color: var(--muted);
font-size: 13px;
}
.team-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.strategy {
border: 1px solid var(--line);
border-radius: var(--radius);
background: #fff;
padding: 14px;
min-height: 190px;
}
.strategy h3 {
margin: 0 0 10px;
font-size: 15px;
}
.mini-flow {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin: 12px 0;
}
.mini-node {
border: 1px solid var(--line);
border-radius: 999px;
padding: 7px 10px;
background: #fbfcff;
color: #283348;
font-size: 12px;
}
.mini-arrow {
color: #8793a8;
}
.matrix {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
}
.stack {
border: 1px solid var(--line);
border-radius: var(--radius);
background: #fff;
padding: 14px;
}
.stack h3 {
margin: 0 0 10px;
font-size: 15px;
}
.stack ul {
margin: 0;
padding-left: 18px;
color: var(--muted);
font-size: 13px;
}
.stack li + li {
margin-top: 6px;
}
.code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 12px;
color: #24324b;
background: #f3f6fb;
border: 1px solid #e5ebf5;
border-radius: 6px;
padding: 2px 5px;
}
@media (max-width: 1180px) {
.architecture-grid,
.matrix,
.diagram-row,
.diagram-row.four,
.diagram-row.six,
.demo-grid {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 760px) {
.page {
padding: 18px;
}
.topbar,
.stage-title {
display: block;
}
.meta {
grid-template-columns: 1fr;
margin-top: 14px;
}
.architecture-grid,
.team-grid,
.matrix,
.primer-grid,
.glossary-grid,
.diagram-row,
.diagram-row.four,
.diagram-row.six,
.demo-grid {
grid-template-columns: 1fr;
}
.diagram-card:not(:last-child)::after {
content: "↓";
right: 50%;
top: auto;
bottom: -10px;
transform: translate(50%, 50%);
}
.lane {
min-height: auto;
}
}
</style>
</head>
<body>
<main class="page">
<header class="topbar">
<div>
<h1>Beaver Backend 可视化</h1>
<p class="subtitle">基于 <span class="code">app-instance/backend</span> 当前代码结构绘制,适合配合讲解使用:先给零基础读者建立概念,再逐页展开 Task、自学习、Skill/Tool、Memory/Session 和 Agent Team。</p>
</div>
<div class="meta" aria-label="visualization metadata">
<a class="pill-link" href="project-comparison.html">项目对比分析</a>
<span class="pill">范围: backend</span>
<span class="pill">入口: Web / CLI / Gateway / MCP</span>
<span class="pill">核心: shared AgentLoop</span>
</div>
</header>
<div class="layout">
<section class="canvas" aria-label="backend visualization">
<nav class="tabs" aria-label="views">
<button class="tab" type="button" data-view="primer" aria-selected="true">入门导读</button>
<button class="tab" type="button" data-view="overview" aria-selected="false">总览</button>
<button class="tab" type="button" data-view="task-detail">Task 概念</button>
<button class="tab" type="button" data-view="learning-detail">自学习</button>
<button class="tab" type="button" data-view="skill-tool-detail">Skill / Tool</button>
<button class="tab" type="button" data-view="memory-detail">Memory / Session</button>
<button class="tab" type="button" data-view="team">Agent Team</button>
<button class="tab" type="button" data-view="request">请求主链</button>
<button class="tab" type="button" data-view="capabilities">能力层</button>
</nav>
<section class="stage active" data-stage="primer">
<div class="stage-title">
<div>
<h2>先把它当成一个“帮用户完成任务的后台工厂”</h2>
<p class="hint">如果你完全没接触过后端、agent、skills、tools先看这一页。它不要求你理解代码细节。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">整体理解:用户一句话如何变成后台执行</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>用户说需求</strong><span>网页、命令行或其他入口收到一句话</span></div>
<div class="diagram-card"><strong>入口接住</strong><span>把请求整理成后端内部格式</span></div>
<div class="diagram-card"><strong>判断类型</strong><span>普通聊天还是需要跟踪的任务</span></div>
<div class="diagram-card"><strong>执行任务</strong><span>选择技能、工具并调用模型</span></div>
<div class="diagram-card"><strong>保存过程</strong><span>记录 session、task、run 和反馈</span></div>
<div class="diagram-card"><strong>返回结果</strong><span>把最终答复展示给用户</span></div>
</div>
</div>
<div class="primer-grid">
<div class="primer-card">
<h3>这个后端在做什么</h3>
<p>用户在前端发一句话,后端负责判断这句话是不是一个任务、要不要查资料或改文件、需不需要拆给多个小助手处理,最后把结果和过程记录下来。</p>
</div>
<div class="primer-card">
<h3>为什么要分这么多层</h3>
<p>因为“接收请求”“决定怎么做”“调用模型”“使用工具”“保存记忆”“学习新技能”是不同职责。分开以后,问题更容易定位,也方便单独替换或测试。</p>
</div>
<div class="primer-card">
<h3>最重要的一句话</h3>
<p>所有真正执行 agent 的地方,最后都会回到同一个 <span class="code">AgentLoop</span>。这保证主 agent 和 sub-agent 用同一套运行规则。</p>
</div>
<div class="primer-card">
<h3>看图时抓住四类东西</h3>
<p>入口负责接话,服务层负责安排,运行内核负责执行,能力层提供工具、技能、记忆和外部连接。</p>
</div>
</div>
<div class="plain-flow">
<div class="plain-step"><strong>用户</strong><p>在网页、命令行或其他渠道输入一句话,比如“帮我整理这个项目的后端架构”。</p></div>
<div class="plain-step"><strong>入口层</strong><p>把这句话接住,整理成后端能理解的请求格式。</p></div>
<div class="plain-step"><strong>服务层</strong><p>判断这是不是一个任务。如果只是闲聊,就简单回答;如果需要执行,就创建或继续一个 Task。</p></div>
<div class="plain-step"><strong>运行内核</strong><p>准备上下文、挑选技能和工具、调用大模型,并在模型要求使用工具时执行工具。</p></div>
<div class="plain-step"><strong>能力层</strong><p>提供文件读写、搜索、记忆、MCP、定时任务、外部集成等具体能力。</p></div>
<div class="plain-step"><strong>状态层</strong><p>记录这次对话、任务、工具结果、验证结果和用户反馈,方便继续任务或沉淀经验。</p></div>
</div>
<div class="glossary-grid">
<div class="glossary-card"><h3>Backend</h3><p>前端背后的服务程序。用户看不见它的界面,但所有保存、调用模型、执行工具都在这里发生。</p></div>
<div class="glossary-card"><h3>Agent</h3><p>可以根据目标自己决定下一步动作的模型运行单元,不只是简单问答。</p></div>
<div class="glossary-card"><h3>Task</h3><p>一个需要跟踪结果的工作项,例如实现功能、分析代码、修复问题。</p></div>
<div class="glossary-card"><h3>Skill</h3><p>给 agent 的专门说明书,告诉它处理某类任务时应该遵循什么步骤和标准。</p></div>
<div class="glossary-card"><h3>Tool</h3><p>agent 可以调用的具体动作,比如读文件、写文件、搜索、执行命令、访问 MCP。</p></div>
<div class="glossary-card"><h3>Memory</h3><p>系统保存的历史、经验、任务结果和反馈,让后续运行可以参考。</p></div>
</div>
<div class="demo">
<h3>Demo一句普通需求如何被后台处理</h3>
<p>适合开场讲解:先不讲代码,只讲用户输入、后台判断、最终输出。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>{
"user_message": "帮我总结 backend 的 Task 机制",
"channel": "web"
}</pre></div>
<div class="demo-block"><h4>后台理解</h4><pre>{
"is_task": true,
"reason": "需要阅读代码并产出解释",
"needs_tools": ["read_file", "search_files"],
"needs_memory": true
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"answer": "Task 是一张可追踪工作单...",
"task_created": true,
"saved_to_session": true,
"can_continue_later": true
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="overview">
<div class="stage-title">
<div>
<h2>模块分层与依赖方向</h2>
<p class="hint">这一页只展示大模块位置和依赖方向,适合先建立全局地图。</p>
</div>
<div class="legend">
<span><i class="dot" style="background: var(--cyan)"></i>入口</span>
<span><i class="dot" style="background: var(--blue)"></i>服务</span>
<span><i class="dot" style="background: var(--green)"></i>运行内核</span>
<span><i class="dot" style="background: var(--violet)"></i>能力</span>
<span><i class="dot" style="background: var(--amber)"></i>状态</span>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">四层架构:从入口到能力</h3>
<div class="diagram-row four">
<div class="diagram-card"><strong>Interfaces</strong><span>Web、CLI、Gateway、MCP 等入口</span></div>
<div class="diagram-card"><strong>Services</strong><span>把请求安排成内部工作流</span></div>
<div class="diagram-card"><strong>Engine</strong><span>统一 AgentLoop 执行模型调用和工具循环</span></div>
<div class="diagram-card"><strong>Capabilities</strong><span>Skills、Tools、Memory、Permissions</span></div>
</div>
</div>
<div class="architecture-grid">
<div class="lane">
<h3>Interfaces 薄入口</h3>
<button class="node selected" data-kind="interface" data-node="web">
<strong>Web FastAPI</strong>
<span>REST、WebSocket、文件、skills、cron、tasks API</span>
</button>
<div class="connector"></div>
<button class="node" data-kind="interface" data-node="cli">
<strong>CLI / Gateway</strong>
<span>命令行和消息网关入口,共用服务层</span>
</button>
<div class="connector"></div>
<button class="node" data-kind="interface" data-node="mcp">
<strong>MCP Servers</strong>
<span>memory_server、tools_server 暴露协议能力</span>
</button>
</div>
<div class="lane">
<h3>Application Services</h3>
<button class="node" data-kind="service" data-node="agent-service">
<strong>AgentService</strong>
<span>接口层统一入口,管理 running/direct 两种调用模式</span>
</button>
<div class="connector"></div>
<button class="node" data-kind="service" data-node="router">
<strong>MainAgentRouter</strong>
<span>把消息路由到 simple chat 或 internal Task mode</span>
</button>
<button class="node" data-kind="service" data-node="tasks">
<strong>TaskService + Validation</strong>
<span>创建任务、记录 run、反馈门控、验证结果</span>
</button>
<button class="node" data-kind="service" data-node="planner">
<strong>任务规划器</strong>
<span>判断单 agent 完成,还是拆成小型 agent team</span>
</button>
</div>
<div class="lane">
<h3>Shared Runtime</h3>
<button class="node" data-kind="engine" data-node="engine-loader">
<strong>EngineLoader</strong>
<span>一次装配 session、memory、skills、tools、MCP</span>
</button>
<div class="connector"></div>
<button class="node" data-kind="engine" data-node="agent-loop">
<strong>AgentLoop</strong>
<span>所有 root agent 和 delegated agent 复用同一运行内核</span>
</button>
<button class="node" data-kind="engine" data-node="providers">
<strong>ProviderBundle</strong>
<span>main / auxiliary / embedding provider 路由</span>
</button>
<button class="node" data-kind="engine" data-node="tool-loop">
<strong>Tool Loop</strong>
<span>LLM 请求、tool calls、tool results、最终回复</span>
</button>
</div>
<div class="lane">
<h3>Capabilities + State</h3>
<button class="node" data-kind="capability" data-node="skills">
<strong>Skills</strong>
<span>catalog、assembler、drafts、reviews、publisher、learning</span>
</button>
<button class="node" data-kind="capability" data-node="tools">
<strong>Tools</strong>
<span>registry、assembler、executor、built-in 和 MCP tools</span>
</button>
<button class="node" data-kind="store" data-node="memory">
<strong>Memory Stores</strong>
<span>session、curated memory、run receipts、skill learning</span>
</button>
<button class="node" data-kind="governance" data-node="permissions">
<strong>Permissions / Authz</strong>
<span>权限 profile、guard、authz-service 集成点</span>
</button>
</div>
</div>
<div class="demo">
<h3>Demo同一个请求经过四层架构</h3>
<p>用一条请求把每层职责串起来,说明每层只做自己的事。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>POST /api/chat
{
"session_id": "web-demo-001",
"message": "请分析这个项目的后端结构"
}</pre></div>
<div class="demo-block"><h4>层级流转</h4><pre>{
"interfaces": "接收 HTTP 请求",
"services": "判断是否进入 Task mode",
"engine": "调用模型并执行工具",
"capabilities": "提供 skill、tool、memory"
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"session_id": "web-demo-001",
"task_id": "task_arch_001",
"message": "后端可以分为入口层、服务层..."
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="task-detail">
<div class="stage-title">
<div>
<h2>Task 的概念:从一句话到可跟踪工作</h2>
<p class="hint">这一页围绕 Intent Agent、主 Agent、Sub-agent 和 Task 展示。讲解重点是:不是所有聊天都是 Task只有需要执行、追踪和反馈的工作才进入 Task mode。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">Task 概念图:谁负责什么</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>用户消息</strong><span>可能是闲聊,也可能是工作请求</span></div>
<div class="diagram-card"><strong>Intent Agent</strong><span>只判断路由,不回答问题</span></div>
<div class="diagram-card"><strong>Task</strong><span>需要追踪的工作单</span></div>
<div class="diagram-card"><strong>主 Agent</strong><span>负责最终答案和整体一致性</span></div>
<div class="diagram-card"><strong>Sub-agent</strong><span>只处理被拆出去的局部工作</span></div>
<div class="diagram-card"><strong>验收反馈</strong><span>满意、修改或放弃都会更新任务状态</span></div>
</div>
</div>
<div class="flow">
<div class="step"><div class="num">1</div><div><h3>用户输入</h3><p>用户可能只是问一句普通问题,也可能要求系统完成一件事,例如“分析后端架构”“修复测试”“整理技能文档”。</p></div></div>
<div class="step"><div class="num">2</div><div><h3>Intent Agent 判断意图</h3><p><span class="code">MainAgentRouter</span> 只做路由,不回答用户。它判断当前消息是 <span class="code">simple_chat</span><span class="code">new_task</span><span class="code">continue_task</span><span class="code">close_task</span> 还是 <span class="code">abandon_task</span></p></div></div>
<div class="step"><div class="num">3</div><div><h3>TaskService 创建或恢复任务</h3><p>如果要进入 Task mode<span class="code">TaskService</span> 会创建 <span class="code">TaskRecord</span>保存目标、状态、run 列表、反馈、验证结果和事件流。</p></div></div>
<div class="step"><div class="num">4</div><div><h3>主 Agent 负责最终回答</h3><p>主 Agent 通过 <span class="code">AgentLoop</span> 运行,负责综合上下文、技能、工具结果和 team 输出,最终给用户一个完整答复。</p></div></div>
<div class="step"><div class="num">5</div><div><h3>Sub-agent 只处理局部工作</h3><p>复杂任务会先交给任务规划器判断是否拆分。Sub-agent 处理调研、检查、实现片段等局部任务,结果再交回主 Agent 综合。</p></div></div>
<div class="step"><div class="num">6</div><div><h3>验证和反馈让 Task 闭环</h3><p>每次 Task run 后会记录 validation。用户点击满意、要求修改或放弃时会更新 Task 状态,并影响后续学习候选。</p></div></div>
</div>
<div class="matrix" style="margin-top:14px">
<div class="stack"><h3>TaskRecord 里有什么</h3><ul><li><span class="code">task_id</span><span class="code">session_id</span>、目标和描述。</li><li><span class="code">status</span> 表示 open、running、awaiting_feedback、closed 等状态。</li><li><span class="code">run_ids</span> 连接每次模型运行。</li><li><span class="code">feedback</span><span class="code">validation_result</span> 记录结果质量。</li></ul></div>
<div class="stack"><h3>Task CRUD</h3><ul><li>Create<span class="code">TaskService.create_task</span></li><li>Read<span class="code">GET /api/tasks</span><span class="code">GET /api/tasks/{task_id}</span></li><li>Updatestart run、append run、record validation、add feedback。</li><li>Delete<span class="code">DELETE /api/tasks/{task_id}</span></li></ul></div>
<div class="stack"><h3>讲解抓手</h3><ul><li>Intent Agent 是分流员。</li><li>Task 是工作单。</li><li>主 Agent 是总负责人。</li><li>Sub-agent 是临时分工人员。</li><li>Validation 和 feedback 是验收记录。</li></ul></div>
</div>
<div class="demo">
<h3>DemoTask 从创建到等待反馈</h3>
<p>这组数据可以用来解释 Task 不是一句回复,而是一张有状态的工作单。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>{
"session_id": "web-demo-001",
"message": "分析 backend 的 Task 机制,并给我讲解稿"
}</pre></div>
<div class="demo-block"><h4>关键数据格式</h4><pre>{
"router_decision": {
"action": "new_task",
"short_title": "Task机制讲解"
},
"task": {
"task_id": "task_001",
"status": "awaiting_feedback",
"run_ids": ["run_001"],
"skill_names": ["backend-reader"]
},
"validation_result": {
"accepted": true,
"score": 0.91
}
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"task_id": "task_001",
"task_status": "awaiting_feedback",
"answer": "Task 机制可以理解为...",
"feedback_options": [
"satisfied",
"revise",
"abandon"
]
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="learning-detail">
<div class="stage-title">
<div>
<h2>自学习:从 Task 反馈到 Skill 生命周期</h2>
<p class="hint">这一页围绕 Task、Skill、自学习 Skill 的 CRUD 展开。讲解重点是:系统不会自动发布新技能,必须经过候选、草稿、安全检查、评估、审核和发布。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">自学习闭环:成功经验如何变成可复用 Skill</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>Task 成功</strong><span>有结果、验证和用户满意反馈</span></div>
<div class="diagram-card"><strong>Learning Candidate</strong><span>系统发现这次经验值得沉淀</span></div>
<div class="diagram-card"><strong>Skill Draft</strong><span>生成一个待审核的技能草稿</span></div>
<div class="diagram-card"><strong>Safety / Eval</strong><span>安全检查和效果评估</span></div>
<div class="diagram-card"><strong>Review</strong><span>人工 approve 或 reject</span></div>
<div class="diagram-card"><strong>Publish</strong><span>发布成可选择的新版本 Skill</span></div>
</div>
</div>
<div class="flow">
<div class="step"><div class="num">1</div><div><h3>Task 产生证据</h3><p>每次 Task run 都会写入 run record、激活过的 skill receipt、tool 使用结果、validation 和用户反馈。</p></div></div>
<div class="step"><div class="num">2</div><div><h3>满意反馈触发候选</h3><p>当用户反馈 <span class="code">satisfied</span> 且 validation 通过时,<span class="code">SkillLearningService</span> 可以基于这次成功经验生成 learning candidate。</p></div></div>
<div class="step"><div class="num">3</div><div><h3>候选生成 Draft</h3><p><span class="code">POST /api/skills/candidates/{candidate_id}/draft</span> 会合成技能草稿,同时生成 safety report 和 eval report。</p></div></div>
<div class="step"><div class="num">4</div><div><h3>人工 Review</h3><p>草稿可 submit、approve 或 reject。高风险内容不能静默发布发布接口需要显式确认。</p></div></div>
<div class="step"><div class="num">5</div><div><h3>Publish / Disable / Rollback</h3><p>通过后进入 published skill后续可以 disable 或 rollback 到指定版本。Worker 只生成和评估,不自动 approve/publish。</p></div></div>
</div>
<div class="matrix" style="margin-top:14px">
<div class="stack"><h3>Candidate CRUD</h3><ul><li>List<span class="code">GET /api/skills/candidates</span></li><li>Read<span class="code">GET /api/skills/candidates/{candidate_id}</span></li><li>Create由满意 Task 反馈或 worker run-once 生成。</li><li>Update合成 draft、regenerate draft、写 audit event。</li></ul></div>
<div class="stack"><h3>Draft / Review CRUD</h3><ul><li>List<span class="code">GET /api/skills/drafts</span></li><li>Readdraft、safety、eval 三类详情接口。</li><li>Updatesubmit、approve、reject。</li><li>Delete底层 <span class="code">DraftService.delete_draft</span> 支持删除草稿。</li></ul></div>
<div class="stack"><h3>Published Skill CRUD</h3><ul><li>Create<span class="code">publish</span> 生成新版本。</li><li>Readskills list、detail、version、file、download。</li><li>Updatedisable、rollback。</li><li>Delete<span class="code">DELETE /api/skills/{name}</span> 删除或归档技能入口。</li></ul></div>
</div>
<div class="demo">
<h3>Demo一次满意反馈如何变成 Skill 草稿</h3>
<p>适合讲“自学习不是自动上线”,它只是生成候选和草稿,后面仍要审核。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>POST /api/chat/feedback
{
"session_id": "web-demo-001",
"run_id": "run_001",
"feedback_type": "satisfied",
"comment": "这次后端讲解结构很好"
}</pre></div>
<div class="demo-block"><h4>关键数据格式</h4><pre>{
"candidate": {
"candidate_id": "cand_001",
"status": "candidate",
"trigger_run_id": "run_001",
"evidence": ["Task 通过验证", "用户满意"]
},
"draft": {
"draft_id": "draft_001",
"skill_name": "backend-explainer",
"status": "draft",
"proposal_kind": "new_skill"
}
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"learning_candidate_created": true,
"draft_created": true,
"safety_report": "passed",
"eval_report": "passed",
"next_step": "submit_review"
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="skill-tool-detail">
<div class="stage-title">
<div>
<h2>Skill 和 Tool如何选技能、选工具以及 Skill 里的 tool 字段</h2>
<p class="hint">这一页关注 Skill 选择器、工具选择器,以及 skill 中工具提示字段如何影响工具暴露。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">Skill / Tool 选择链路</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>任务描述</strong><span>本轮要解决的问题</span></div>
<div class="diagram-card"><strong>Skill 召回</strong><span>embedding 找到候选 Skill</span></div>
<div class="diagram-card"><strong>Skill 精选</strong><span>LLM 选择真正激活的 Skill</span></div>
<div class="diagram-card"><strong>tool_hints</strong><span>Skill 建议常用工具</span></div>
<div class="diagram-card"><strong>Tool 选择</strong><span>always tools + hints + embedding top-k</span></div>
<div class="diagram-card"><strong>Tool Schema</strong><span>只把选中的工具暴露给模型</span></div>
</div>
</div>
<div class="flow">
<div class="step"><div class="num">1</div><div><h3>Skill 选择器先看任务</h3><p><span class="code">SkillAssembler</span> 读取所有可选 skill 摘要,用 embedding 召回候选,再让辅助模型从候选中选出本轮真正激活的 skill。</p></div></div>
<div class="step"><div class="num">2</div><div><h3>激活 Skill 变成上下文</h3><p>被选中的 skill 会变成 <span class="code">SkillContext</span>,写入 system prompt并生成 <span class="code">SkillActivationReceipt</span> 方便后续学习和审计。</p></div></div>
<div class="step"><div class="num">3</div><div><h3>Skill 的 tool_hints 影响工具选择</h3><p>Skill 版本里有 <span class="code">tool_hints</span>。如果某个 skill 明确提示需要 <span class="code">read_file</span><span class="code">patch_file</span> 等工具,工具选择器会优先加入这些工具。</p></div></div>
<div class="step"><div class="num">4</div><div><h3>工具选择器再补充工具</h3><p><span class="code">ToolAssembler</span> 先加入 always tools再加入 skill hints再通过 embedding 从 registry 中召回更多相关工具。</p></div></div>
<div class="step"><div class="num">5</div><div><h3>ToolRegistry 导出 schema</h3><p><span class="code">ToolRegistry</span> 不执行工具,只把选中的 <span class="code">ToolSpec</span> 导出成 provider 可消费的 function schema。</p></div></div>
<div class="step"><div class="num">6</div><div><h3>ToolExecutor 执行调用</h3><p>模型返回 tool call 后,<span class="code">ToolExecutor</span> 执行工具,并把 tool result 写回 session history供下一轮模型继续使用。</p></div></div>
</div>
<div class="matrix" style="margin-top:14px">
<div class="stack"><h3>Skill 中关键字段</h3><ul><li><span class="code">name</span>:技能唯一名。</li><li><span class="code">description</span>:选择器理解技能用途。</li><li><span class="code">content</span>:真正注入给 agent 的指导正文。</li><li><span class="code">tool_hints</span>:建议本 skill 常用哪些工具。</li><li><span class="code">tags</span><span class="code">owners</span>:分类和治理信息。</li></ul></div>
<div class="stack"><h3>ToolSpec 中关键字段</h3><ul><li><span class="code">name</span>:模型调用函数名。</li><li><span class="code">description</span>:模型理解工具何时可用。</li><li><span class="code">input_schema</span>:参数结构。</li><li><span class="code">toolset</span>:所属工具集。</li><li><span class="code">always_available</span>:是否每轮都暴露。</li></ul></div>
<div class="stack"><h3>选择顺序</h3><ul><li>Skill候选召回 -> LLM shortlist -> LLM final -> 注入上下文。</li><li>Toolalways tools -> skill tool_hints -> embedding top-k。</li><li>最终:只把选中的工具 schema 给模型,减少噪音和误用。</li></ul></div>
</div>
<div class="demo">
<h3>DemoSkill 选择器和工具选择器如何配合</h3>
<p>用一个 Skill 的 frontmatter 解释 <span class="code">tool_hints</span> 为什么会影响本轮可用工具。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>{
"task_description": "阅读 backend 代码并解释 Task 机制"
}</pre></div>
<div class="demo-block"><h4>关键数据格式</h4><pre>---
name: backend-explainer
description: Explain backend architecture
tool_hints:
- search_files
- read_file
- session_search
---
先定位入口,再追踪服务层和运行内核。</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"activated_skills": [
"backend-explainer"
],
"selected_tools": [
"memory",
"session_search",
"search_files",
"read_file"
],
"tool_schema_count": 4
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="memory-detail">
<div class="stage-title">
<div>
<h2>Memory 和 SessionCRUD、装载与运行时快照</h2>
<p class="hint">这一页解释会话、记忆和运行记录如何创建、读取、更新、归档,以及 AgentLoop 如何装载它们。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">Memory / Session 装载和写回</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>EngineLoader</strong><span>创建状态组件</span></div>
<div class="diagram-card"><strong>Session</strong><span>保存对话消息和事件</span></div>
<div class="diagram-card"><strong>Memory Snapshot</strong><span>每次 run 捕获一份快照</span></div>
<div class="diagram-card"><strong>AgentLoop</strong><span>用快照组装上下文并执行</span></div>
<div class="diagram-card"><strong>Run Memory</strong><span>记录运行证据和 skill effect</span></div>
<div class="diagram-card"><strong>Feedback</strong><span>反馈反写到任务和学习数据</span></div>
</div>
</div>
<div class="flow">
<div class="step"><div class="num">1</div><div><h3>EngineLoader 装载状态组件</h3><p><span class="code">EngineLoader.load</span> 创建 <span class="code">SessionManager</span>、curated <span class="code">MemoryStore</span><span class="code">MemoryService</span><span class="code">RunMemoryStore</span><span class="code">SkillLearningStore</span></p></div></div>
<div class="step"><div class="num">2</div><div><h3>Session 保存对话过程</h3><p>每次 run 都会确保 session 存在,并追加 system、user、assistant、tool 等消息,同时记录 event payload、usage、run_id 和上下文可见性。</p></div></div>
<div class="step"><div class="num">3</div><div><h3>MemoryService 捕获快照</h3><p>AgentLoop 每次运行都会调用 <span class="code">capture_snapshot_for_run</span>。并行 team run 各拿自己的 frozen snapshot避免互相覆盖。</p></div></div>
<div class="step"><div class="num">4</div><div><h3>RunMemoryStore 保存运行证据</h3><p>run record 记录输入、输出、激活 skill、验证、反馈skill effect 记录某个 skill 在这次 run 中的效果。</p></div></div>
<div class="step"><div class="num">5</div><div><h3>API 提供 Session CRUD</h3><p>前端通过 sessions API 创建、查看、归档会话,也可以读取 session process 和 debug chat logs。</p></div></div>
</div>
<div class="matrix" style="margin-top:14px">
<div class="stack"><h3>Session CRUD</h3><ul><li>Create<span class="code">POST /api/sessions/{session_id}</span> 或 run 时 <span class="code">ensure_session</span></li><li>Read<span class="code">GET /api/sessions</span><span class="code">GET /api/sessions/{session_id}</span></li><li>Update<span class="code">append_message</span><span class="code">update_usage</span><span class="code">update_system_prompt</span></li><li>Delete/Archive<span class="code">DELETE /api/sessions/{session_id}</span> 或 archive。</li></ul></div>
<div class="stack"><h3>Memory / Run CRUD</h3><ul><li>Createappend run record、append skill effect、curated memory item。</li><li>Readsession search、memory tool、run list、skill effects。</li><li>Updatevalidation、feedback、success ratio、performance snapshot。</li><li>Archive通过 session end reason 或 skill/version 状态保留历史。</li></ul></div>
<div class="stack"><h3>装载顺序</h3><ul><li>配置解析 workspace。</li><li>初始化 curated memory store。</li><li>创建 session 和 run stores。</li><li>注入 ToolContext services。</li><li>运行时按 run 捕获 memory snapshot。</li></ul></div>
</div>
<div class="demo">
<h3>DemoSession、Message、Memory Snapshot 的关系</h3>
<p>适合讲“为什么能继续对话”,以及“为什么并行 sub-agent 不会互相污染记忆”。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>POST /api/sessions/web-demo-001
POST /api/chat
{
"session_id": "web-demo-001",
"message": "继续解释刚才的 Task"
}</pre></div>
<div class="demo-block"><h4>关键数据格式</h4><pre>{
"session": {
"id": "web-demo-001",
"source": "web",
"message_count": 12
},
"message": {
"role": "user",
"run_id": "run_002",
"content": "继续解释刚才的 Task"
},
"memory_snapshot": {
"captured_for_run": "run_002",
"frozen": true
}
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"session_loaded": true,
"history_used": true,
"run_id": "run_002",
"assistant_message_saved": true
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="request">
<div class="stage-title">
<div>
<h2>一次用户请求如何流过后端</h2>
<p class="hint">从 WebSocket/HTTP 进入,到 AgentLoop 选择 skills/tools最后写回 session 和 run memory。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">请求主链:技术视角</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>HTTP / WS</strong><span>接口收到用户请求</span></div>
<div class="diagram-card"><strong>AgentService</strong><span>统一收口 direct / running 模式</span></div>
<div class="diagram-card"><strong>Router</strong><span>判断 simple chat 或 Task mode</span></div>
<div class="diagram-card"><strong>Planner</strong><span>选择 single 或 team</span></div>
<div class="diagram-card"><strong>AgentLoop</strong><span>模型调用和工具循环</span></div>
<div class="diagram-card"><strong>Validation</strong><span>记录验证、反馈和学习证据</span></div>
</div>
</div>
<div class="flow">
<div class="step"><div class="num">1</div><div><h3>接口接收请求</h3><p><span class="code">interfaces/web/app.py</span> 提供 <span class="code">/api/chat</span><span class="code">/ws/{session_id}</span>、tasks、files、skills、cron 等入口,只做参数转换和响应拼装。</p></div></div>
<div class="step"><div class="num">2</div><div><h3>AgentService 收口</h3><p>接口层不直接 new loop而是调用 <span class="code">AgentService.process_direct</span><span class="code">submit_direct</span>,由 service 管理 direct/running mode。</p></div></div>
<div class="step"><div class="num">3</div><div><h3>Intent Agent 路由</h3><p><span class="code">MainAgentRouter</span> 用辅助模型判断 simple chat、继续任务、新建任务、关闭或放弃任务simple chat 会关闭 skill/tool assembly。</p></div></div>
<div class="step"><div class="num">4</div><div><h3>Task mode 规划</h3><p><span class="code">TaskService</span> 创建或恢复任务,任务规划器决定单 agent 还是 teamteam 模式先运行 sub-agent再交给主 agent synthesis。</p></div></div>
<div class="step"><div class="num">5</div><div><h3>EngineLoader 装配运行时</h3><p>统一加载 session manager、memory service、skills loader、tool registry、tool executor、skill learning pipeline、agent registry、MCP manager。</p></div></div>
<div class="step"><div class="num">6</div><div><h3>AgentLoop 运行主链</h3><p>捕获 memory snapshot组装 prompt选择 skills 和 tools调用 provider若返回 tool calls则执行 tool loop 并把结果追加回上下文。</p></div></div>
<div class="step"><div class="num">7</div><div><h3>验证、反馈和学习沉淀</h3><p>Task 结果进入 validation 和 feedback gate满意反馈会更新 run record、skill effects并可能生成 assisted learning candidate。</p></div></div>
</div>
<div class="demo">
<h3>Demo完整 /api/chat 输入输出</h3>
<p>这可以作为接口级例子:用户输入什么,后端可能返回什么。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>POST /api/chat
{
"session_id": "web-demo-001",
"message": "帮我画出 Task、自学习、Skill 和 Memory 的关系",
"thinking_enabled": true
}</pre></div>
<div class="demo-block"><h4>关键内部事件</h4><pre>[
{"event_type": "intent_agent_decision", "action": "new_task"},
{"event_type": "task_execution_planned", "mode": "team"},
{"event_type": "skill_activation_snapshotted", "skills": ["backend-explainer"]},
{"event_type": "tool_selection_snapshotted", "tools": ["search_files", "read_file"]},
{"event_type": "task_validation_snapshotted", "accepted": true}
]</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"session_id": "web-demo-001",
"run_id": "run_003",
"task_id": "task_002",
"task_status": "awaiting_feedback",
"message": "可以把这四者理解为..."
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="team">
<div class="stage-title">
<div>
<h2>Agent Team什么时候拆分、怎么编排、如何回到主 Agent</h2>
<p class="hint">这一页展示 Agent Team 的完整概念:注册的 agent 能力、Task planner 的 team plan、ExecutionGraph 的三种策略、每个节点的 skill 绑定,以及最终 synthesis。</p>
</div>
</div>
<div class="diagram">
<h3 class="diagram-title">Agent Team 执行图</h3>
<div class="diagram-row six">
<div class="diagram-card"><strong>Task</strong><span>复杂工作进入任务模式</span></div>
<div class="diagram-card"><strong>Team Plan</strong><span>Planner 生成执行图</span></div>
<div class="diagram-card"><strong>Skill Binding</strong><span>为每个节点绑定 Skill 或临时指导</span></div>
<div class="diagram-card"><strong>Scheduler</strong><span>按 sequence、parallel 或 DAG 推进</span></div>
<div class="diagram-card"><strong>Sub-agents</strong><span>节点回到同一个 AgentLoop 执行</span></div>
<div class="diagram-card"><strong>Main Synthesis</strong><span>主 Agent 综合所有节点输出</span></div>
</div>
</div>
<div class="flow" style="margin-bottom:14px">
<div class="step"><div class="num">1</div><div><h3>先判断是否值得组队</h3><p>任务规划器只在独立调研、评审、实现切片、分阶段检查能明显提升结果时选择 team否则保持 single agent。</p></div></div>
<div class="step"><div class="num">2</div><div><h3>生成 ExecutionGraph</h3><p>team plan 会生成 <span class="code">ExecutionGraph</span>,包含 strategy、nodes、node task、depends_on、expected_output 和 skill_query。</p></div></div>
<div class="step"><div class="num">3</div><div><h3>为节点绑定 Skill</h3><p><span class="code">TaskSkillResolver</span> 为每个 node 选择 published skill如果没有合适 skill就合成 one-run ephemeral guidance。</p></div></div>
<div class="step"><div class="num">4</div><div><h3>LocalAgentRunner 执行节点</h3><p>每个 sub-agent 节点都会通过 <span class="code">LocalAgentRunner</span> 调回同一个 <span class="code">AgentLoop</span>,只是 session_id、source、execution_context 不同。</p></div></div>
<div class="step"><div class="num">5</div><div><h3>主 Agent 综合输出</h3><p>Team 的 node outputs 不直接作为最终答案,而是进入主 Agent 的 synthesis context由主 Agent 负责最终一致性、取舍和用户回答。</p></div></div>
</div>
<div class="team-grid">
<div class="strategy">
<h3>Sequence</h3>
<div class="mini-flow">
<span class="mini-node">node A</span><span class="mini-arrow"></span><span class="mini-node">node B</span><span class="mini-arrow"></span><span class="mini-node">main synthesis</span>
</div>
<p class="hint">上游输出作为下游 dependency output任一节点失败后续节点被标记 blocked。</p>
</div>
<div class="strategy">
<h3>Parallel</h3>
<div class="mini-flow">
<span class="mini-node">node A</span><span class="mini-node">node B</span><span class="mini-node">node C</span><span class="mini-arrow"></span><span class="mini-node">synthesis</span>
</div>
<p class="hint">适合独立调研、并行检查或拆分实现面;由 <span class="code">asyncio.gather</span> 并发运行。</p>
</div>
<div class="strategy">
<h3>DAG</h3>
<div class="mini-flow">
<span class="mini-node">research</span><span class="mini-arrow"></span><span class="mini-node">design</span><span class="mini-arrow"></span><span class="mini-node">review</span>
</div>
<p class="hint">显式 <span class="code">depends_on</span> 控制依赖scheduler 按 ready batch 推进并检测循环依赖。</p>
</div>
<div class="strategy">
<h3>Skill Binding</h3>
<div class="mini-flow">
<span class="mini-node">skill query</span><span class="mini-arrow"></span><span class="mini-node">published skill</span><span class="mini-arrow">/</span><span class="mini-node">ephemeral guidance</span>
</div>
<p class="hint"><span class="code">TaskSkillResolver</span> 优先 pin 已发布 skill缺失时合成 one-run guidance不自动发布。</p>
</div>
</div>
<div class="matrix" style="margin-top:14px">
<div class="stack"><h3>Agent Team CRUD</h3><ul><li>List<span class="code">GET /api/agents</span><span class="code">GET /api/subagents</span></li><li>Create<span class="code">POST /api/agents</span><span class="code">POST /api/subagents</span></li><li>Update<span class="code">PATCH /api/agents/{agent_id}</span><span class="code">PUT /api/subagents/{agent_id}</span>、disable。</li><li>Delete<span class="code">DELETE /api/agents/{agent_id}</span><span class="code">DELETE /api/subagents/{agent_id}</span></li></ul></div>
<div class="stack"><h3>节点输入里有什么</h3><ul><li>父 task id 和父 run id。</li><li>节点自己的 task 和 expected output。</li><li>依赖节点的输出。</li><li>pinned skills 或 ephemeral guidance。</li><li>节点角色、约束和 skill selection context。</li></ul></div>
<div class="stack"><h3>失败如何处理</h3><ul><li>Sequence 中前序失败会阻塞后续节点。</li><li>DAG 中依赖失败会阻塞依赖它的节点。</li><li>Parallel 节点独立运行,失败会进入 team summary。</li><li>主 Agent 会看到失败摘要,再决定如何向用户说明。</li></ul></div>
</div>
<div class="demo">
<h3>DemoAgent Team 把复杂任务拆成三个节点</h3>
<p>这个例子适合讲 sequence、parallel、DAG 之前先让用户理解“节点输出最后还要由主 Agent 综合”。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>{
"task_id": "task_002",
"user_message": "检查后端架构讲解是否完整,并补上缺口"
}</pre></div>
<div class="demo-block"><h4>关键数据格式</h4><pre>{
"mode": "team",
"strategy": "dag",
"nodes": [
{"node_id": "read", "task": "阅读现有文档", "depends_on": []},
{"node_id": "check", "task": "检查缺失主题", "depends_on": ["read"]},
{"node_id": "draft", "task": "补写讲解内容", "depends_on": ["check"]}
]
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"team_success": true,
"node_results": [
{"node_id": "read", "success": true},
{"node_id": "check", "success": true},
{"node_id": "draft", "success": true}
],
"main_synthesis": "已补充 Task、自学习、Skill/Tool、Memory/Session 和 Agent Team 示例。"
}</pre></div>
</div>
</div>
</section>
<section class="stage" data-stage="capabilities">
<div class="stage-title">
<div>
<h2>能力层和状态边界</h2>
<p class="hint">这些层围绕 AgentLoop 工作,但各自保持独立职责。</p>
</div>
</div>
<div class="matrix">
<div class="stack">
<h3>Skills</h3>
<ul>
<li><span class="code">SkillsLoader</span> 读取 published skill 和 selection candidates。</li>
<li><span class="code">SkillAssembler</span> 通过 embedding 召回和 LLM 决策激活 skill。</li>
<li>draft、review、publisher、learning pipeline 支持候选生成、审核和发布。</li>
</ul>
</div>
<div class="stack">
<h3>Tools</h3>
<ul>
<li><span class="code">ToolRegistry</span> 只负责注册、查找和导出 provider schema。</li>
<li><span class="code">ToolAssembler</span> 结合 always tools、skill hints 和 embedding top-k。</li>
<li><span class="code">ToolExecutor</span> 执行 tool call结果写入 session history。</li>
</ul>
</div>
<div class="stack">
<h3>Memory</h3>
<ul>
<li>每个 run 捕获自己的 frozen memory snapshot避免并行 team run 串扰。</li>
<li>session manager 保存消息、事件 payload、usage、归档状态。</li>
<li>run memory 保存 receipts、validation、feedback、skill effects。</li>
</ul>
</div>
<div class="stack">
<h3>Providers</h3>
<ul>
<li><span class="code">ProviderBundle</span> 分离 main、auxiliary、embedding runtime。</li>
<li>router、planner、skill selection 可走 auxiliary provider。</li>
<li>主回答、tool loop 和 synthesis 走 main provider。</li>
</ul>
</div>
<div class="stack">
<h3>Integrations</h3>
<ul>
<li>MCP manager 连接外部 MCP server并把 tools 注册进 registry。</li>
<li>Outlook、WhatsApp、A2A、authz 保持在 integrations 边界内。</li>
<li>Web API 只暴露集成状态、连接测试和数据读取入口。</li>
</ul>
</div>
<div class="stack">
<h3>Cron</h3>
<ul>
<li><span class="code">CronService</span> 在 FastAPI lifespan 中随 AgentService 启停。</li>
<li>notification 生成通知结果task mode 生成可反馈的 TaskRecord。</li>
<li>用户 engage 后可把定时结果转成继续编辑的任务。</li>
</ul>
</div>
</div>
<div class="demo">
<h3>Demo一次运行会同时用到哪些能力</h3>
<p>适合收尾时复盘:一次 Task 运行不是只调用模型,而是多个能力层一起工作。</p>
<div class="demo-grid">
<div class="demo-block"><h4>输入</h4><pre>{
"task": "生成后端架构讲解页",
"session_id": "web-demo-001"
}</pre></div>
<div class="demo-block"><h4>能力调用</h4><pre>{
"providers": ["main", "auxiliary", "embedding"],
"skills": ["backend-explainer"],
"tools": ["search_files", "read_file", "write_file"],
"memory": ["session_history", "run_record"],
"integrations": ["mcp_optional"]
}</pre></div>
<div class="demo-block"><h4>预期输出</h4><pre>{
"artifact": "backend-visualization.html",
"session_updated": true,
"run_memory_written": true,
"skill_effect_recorded": true
}</pre></div>
</div>
</div>
</section>
</section>
</div>
</main>
<script>
const tabs = Array.from(document.querySelectorAll(".tab"));
const stages = Array.from(document.querySelectorAll(".stage"));
tabs.forEach((tab) => {
tab.addEventListener("click", () => {
const view = tab.dataset.view;
tabs.forEach((item) => item.setAttribute("aria-selected", String(item === tab)));
stages.forEach((stage) => stage.classList.toggle("active", stage.dataset.stage === view));
});
});
document.querySelectorAll(".node").forEach((node) => {
node.addEventListener("click", () => {
document.querySelectorAll(".node").forEach((candidate) => candidate.classList.remove("selected"));
node.classList.add("selected");
});
});
</script>
</body>
</html>