feat: 场景 C 重写为文档解析场景,DocumentCard 增加「查看解析」交互

- DocumentSegment 新增 parsedContent 字段,存储 AI 对文档的解析结果
- DocumentCard 增加「查看解析 / 收起解析」按钮,展开后以 Markdown 渲染解析内容
- 场景 C 从「长文本+文档+多模态」改为「单文档解析」场景,聚焦展示解析功能
- ChatContext 默认 activeDemo 索引修正为 4
This commit is contained in:
carry
2026-06-07 23:12:34 +08:00
parent b8e4961d10
commit 290cc55abf
6 changed files with 435 additions and 210 deletions
+57 -13
View File
@@ -1,6 +1,8 @@
import { useState } from 'react'
import type { DocumentSegment } from '../../types/protocol' import type { DocumentSegment } from '../../types/protocol'
import type { LucideIcon } from 'lucide-react' import type { LucideIcon } from 'lucide-react'
import { FileText, FileImage, FileAudio, File } from 'lucide-react' import { FileText, FileImage, FileAudio, File, ChevronDown, ChevronRight, Eye, EyeOff } from 'lucide-react'
import MarkdownRenderer from '../MarkdownRenderer'
const mimeIcons: Record<string, LucideIcon> = { const mimeIcons: Record<string, LucideIcon> = {
'text/': FileText, 'text/': FileText,
@@ -22,21 +24,63 @@ function formatBytes(bytes: number): string {
} }
export default function DocumentCard({ segment }: { segment: DocumentSegment }) { export default function DocumentCard({ segment }: { segment: DocumentSegment }) {
const [showParsed, setShowParsed] = useState(false)
return ( return (
<div className="my-2 flex items-start gap-3 rounded-lg border border-gray-200 bg-white p-3 hover:shadow-sm transition-shadow"> <div className="my-2 rounded-lg border border-gray-200 bg-white overflow-hidden hover:shadow-sm transition-shadow">
<div className="shrink-0 mt-0.5">{getIcon(segment.mimeType)}</div> {/* 文档信息卡片 */}
<div className="flex-1 min-w-0"> <div className="flex items-start gap-3 p-3">
<div className="flex items-center gap-2 flex-wrap"> <div className="shrink-0 mt-0.5">{getIcon(segment.mimeType)}</div>
<span className="text-sm font-medium text-gray-800 truncate"> <div className="flex-1 min-w-0">
{segment.fileName} <div className="flex items-center gap-2 flex-wrap">
</span> <span className="text-sm font-medium text-gray-800 truncate">
<span className="text-xs text-gray-400">{formatBytes(segment.sizeBytes)}</span> {segment.fileName}
</span>
<span className="text-xs text-gray-400">{formatBytes(segment.sizeBytes)}</span>
</div>
<p className="text-xs text-gray-400 mt-0.5">{segment.mimeType}</p>
{!showParsed && (
<p className="text-xs text-gray-500 mt-1.5 line-clamp-3 italic">
{segment.snippet}
</p>
)}
</div> </div>
<p className="text-xs text-gray-400 mt-0.5">{segment.mimeType}</p>
<p className="text-xs text-gray-500 mt-1.5 line-clamp-3 italic"> {/* 查看解析按钮 */}
{segment.snippet} {segment.parsedContent && (
</p> <button
onClick={() => setShowParsed(!showParsed)}
className="shrink-0 flex items-center gap-1 px-2.5 py-1.5 rounded-md text-xs font-medium transition-colors
bg-blue-50 text-blue-600 hover:bg-blue-100"
>
{showParsed ? (
<><EyeOff size={13} /> </>
) : (
<><Eye size={13} /> </>
)}
</button>
)}
</div> </div>
{/* 解析结果展开区 */}
{showParsed && segment.parsedContent && (
<div className="border-t border-gray-100">
<div className="flex items-center gap-1.5 px-3 pt-2 pb-1">
<FileText size={12} className="text-blue-400" />
<span className="text-[11px] font-medium text-blue-500"></span>
<div className="flex-1" />
<button
onClick={() => setShowParsed(false)}
className="text-gray-400 hover:text-gray-600"
>
<ChevronDown size={14} />
</button>
</div>
<div className="px-3 pb-3 max-h-80 overflow-y-auto text-sm">
<MarkdownRenderer content={segment.parsedContent} />
</div>
</div>
)}
</div> </div>
) )
} }
+2 -2
View File
@@ -13,8 +13,8 @@ interface ChatContextValue {
const ChatContext = createContext<ChatContextValue | null>(null) const ChatContext = createContext<ChatContextValue | null>(null)
export function ChatProvider({ children }: { children: ReactNode }) { export function ChatProvider({ children }: { children: ReactNode }) {
const [activeDemo, setActiveDemo] = useState(5) // Default: Real Skills Demo F const [activeDemo, setActiveDemo] = useState(4) // Default: Scene F
const [envelope, setEnvelope] = useState<PromptEnvelope>(demos[5].envelope) const [envelope, setEnvelope] = useState<PromptEnvelope>(demos[4].envelope)
const switchDemo = (i: number) => { const switchDemo = (i: number) => {
setActiveDemo(i) setActiveDemo(i)
+4 -4
View File
@@ -28,8 +28,8 @@ export const demos: DemoScenario[] = [
}, },
{ {
id: 'c', id: 'c',
label: '场景 C', label: '场景 C 📄',
description: '长文本 + 文档附件 + 多模态', description: '文档解析:点击「查看解析」看 AI 如何提取文档内容',
envelope: demoC, envelope: demoC,
}, },
{ {
@@ -40,8 +40,8 @@ export const demos: DemoScenario[] = [
}, },
{ {
id: 'e', id: 'e',
label: '场景 E 🧪', label: '场景 E 🔍',
description: 'Skills 渐进式披露 + Agent 主动触发 /deep-research', description: '日志分析:异常检测 + 安全审计 + 性能分析',
envelope: demoE, envelope: demoE,
}, },
{ {
+91 -57
View File
@@ -1,57 +1,66 @@
/**
* Demo C — 文档解析(核心展示)
*
* 场景:用户上传多份文档请求 AI 进行解析,展示文档上传后 AI 如何
* 提取、结构化理解其中的内容。
*
* 关键展示:
* 1. 一份 PDF 文档,右上角有「查看解析」按钮
* 2. 点击后展开显示 AI 对文档的解析结果(Markdown 渲染)
* 3. Assistant 基于解析结果给出分析回答
* 4. 无 long_text / media / 多文档干扰 —— 聚焦单文档解析体验
*/
import type { PromptEnvelope } from '../../types/protocol' import type { PromptEnvelope } from '../../types/protocol'
import { getSkills } from '../skills' import { getSkills } from '../skills'
const now = Date.now() const now = Date.now()
const longArticleContent_C = `# 大语言模型交互中的上下文透明性问题 /** PDF 市场调研报告的解析结果 */
const marketReportParsed = `## 文档概览
## 摘要 | 字段 | 内容 |
|------|------|
| 标题 | 2026 年 Q2 智能助手市场研究报告 |
| 作者 | 市场分析部 · 陈敏 |
| 日期 | 2026 年 5 月 28 日 |
| 页数 | 42 页 |
| 语言 | 中文(简体) |
近年来,以 ChatGPT 为代表的对话式 AI 产品迅速普及。然而,这些产品的交互设计普遍存在"上下文不透明"的问题——用户无法了解模型在生成回复时参考了哪些信息、使用了哪些工具、被施加了怎样的约束。 ## 核心发现
## 1. 问题定义 ### 1. 市场规模
2026 年 Q2 全球智能助手市场规模预计达到 **187 亿美元**,同比增长 **34.2%**。
当前的聊天界面(chatbox UI)将 LLM 的完整上下文封装在黑盒之中。用户看到的是一个"魔法对话框":输入问题,得到回答。但这个过程掩盖了大量关键信息 主要增长驱动力
- 企业级 AI 助手采纳率从 2025 年的 38% 提升至 56%
- 多模态能力(图像/语音/代码)推动使用场景扩展
- 开源模型的成熟降低了部署门槛
- **System Prompt**:模型的行为准则和角色设定,直接决定了回复的风格和边界 ### 2. 竞争格局
- **User Memory**:跨对话持久化的用户信息,可能包含过时或不准确的记忆
- **Tools & Skills**:模型可调用的外部能力,用户可能完全不知道它们的存在
- **Variable Injection**:模板变量在用户不知情的情况下被替换为具体值
这种不透明性导致了一系列用户体验问题:信任缺失、纠错困难、意外行为难以解释。 | 厂商 | 市场份额 | QoQ 变化 | 核心优势 |
|------|---------|---------|---------|
| OpenAI | 41% | +2.3% | 品牌认知度 + 开发者生态 |
| Anthropic | 18% | +5.1% | 安全对齐 + 长上下文 |
| Google | 15% | -1.2% | 搜索整合 + 多模态 |
| Meta | 12% | +3.8% | 开源策略 + 成本优势 |
| 其他 | 14% | — | 垂直领域玩家 |
## 2. 设计目标 ### 3. 用户需求变化
- **可信度**成为用户选择助手的第一要素(47% 受访者提及)
- **上下文窗口大小**的优先级从 2025 年的第 7 位跃升至第 3 位
- 企业用户对 \`system prompt\` 透明度的需求同比增长 **82%**
- 工具调用(Function Calling)的使用率从 23% 增长到 51%
本文提出一套"Prompt Envelope Protocol"——一种结构化的 prompt 表达格式,使得: ### 4. 关键趋势
> "智能助手的竞争从模型能力转向体验设计。用户不再只关心'能不能答对',更关心'我能不能理解你为什么这么回答'。"——报告结语`
1. 每种上下文元素都有明确的视觉呈现
2. 用户可以按需展开或折叠细节
3. 协议可以无损导出为标准 API 格式
4. 视觉语言保持简约,不增加认知负荷
## 3. 核心设计原则
### 3.1 信息密度梯度
核心对话文本始终可见,元信息默认折叠。用户不会在每次对话中都被无关的 system prompt 和工具列表淹没。
### 3.2 颜色编码系统
每种上下文类型有独立的颜色标记,形成可学习的视觉语言:
- 蓝色 = 变量
- 灰色 = 系统指令
- 紫色 = 用户记忆
- 绿色 = 技能
- 橙色 = 工具
### 3.3 协议即视图
折叠状态存储在协议数据中而非 UI 状态中。这意味着相同的协议数据在任何渲染器下都产生相同的视图——协议本身就是 view model。`
export const demoC: PromptEnvelope = { export const demoC: PromptEnvelope = {
version: '1.0', version: '1.0',
model: 'gpt-4-turbo', model: 'gpt-4-turbo',
messages: [ messages: [
// --- System message ---
{ {
id: 'c-1', id: 'c-1',
role: 'system', role: 'system',
@@ -72,58 +81,83 @@ export const demoC: PromptEnvelope = {
kind: 'system_prompt', kind: 'system_prompt',
content: `当前日期:{{current_date}},回复语言:{{language}}。 content: `当前日期:{{current_date}},回复语言:{{language}}。
你是文档审阅助手。帮助用户分析文档、提取要点、回答关于文档内容的问题。`, 你是文档解析助手。帮助用户分析上传的文档、提取关键信息、回答关于文档内容的问题。
解析文档后,你会输出结构化的解析结果,并在回复中注明关键发现。`,
collapsed: true, collapsed: true,
}, },
{ {
kind: 'skills', kind: 'skills',
description: description:
'Skills 是模型可调用的内置能力(slash commands)。输入 / 开头即可触发,无需等待模型推理。当前对话中启用以下 skills', 'Skills 是模型可调用的内置能力(slash commands)。当前对话中启用以下 skills',
items: getSkills(['summarize', 'translate', 'qa']), items: getSkills(['summarize', 'translate', 'qa']),
collapsed: true, collapsed: true,
}, },
], ],
timestamp: now - 150000, timestamp: now - 150000,
}, },
// --- User 上传文档请求解析 ---
{ {
id: 'c-2', id: 'c-2',
role: 'user', role: 'user',
segments: [ segments: [
{ {
kind: 'text', kind: 'text',
content: '帮我审阅这篇论文草稿,看看结构上有什么问题:', content: '帮我解析这份市场研究报告,看看有什么关键发现。',
},
{
kind: 'long_text',
content: longArticleContent_C,
charCount: longArticleContent_C.length,
collapsed: true,
}, },
{ {
kind: 'document', kind: 'document',
fileName: 'hci-paper-draft.pdf', fileName: '2026-Q2-智能助手市场报告.pdf',
mimeType: 'application/pdf', mimeType: 'application/pdf',
snippet: sizeBytes: 2_845_000,
'# 大语言模型交互中的上下文透明性问题\n\n## 摘要\n\n近年来,以 ChatGPT 为代表的对话式 AI 产品迅速普及。然而,这些产品的交互设计普遍存在"上下文不透明"的问题——用户无法了解模型在生成回复时参考了哪些信息...', snippet: '# 2026 年 Q2 智能助手市场研究报告\n\n## 摘要\n\n2026 年 Q2 全球智能助手市场规模预计达到 187 亿美元,同比增长 34.2%。主要增长驱动力包括企业级 AI 助手采纳率提升…',
sizeBytes: 245760, parsedContent: marketReportParsed,
},
{
kind: 'media',
mediaType: 'image',
url: '',
altText: '论文框架图:Context Layers 分层示意图',
}, },
], ],
timestamp: now - 120000, timestamp: now - 120000,
}, },
// --- Assistant 综合回复 ---
{ {
id: 'c-3', id: 'c-3',
role: 'assistant', role: 'assistant',
segments: [ segments: [
{ {
kind: 'text', kind: 'text',
content: content: `文档已解析完成。以下是报告中的关键发现:
'我读完了你的草稿。整体框架很清晰,但有几个建议:\n\n1. **第3节的设计原则**是目前最强的部分,可以考虑将这部分提前到第2节\n2. "信息密度梯度"这个概念很有原创性,建议在摘要中就提及\n3. 缺少用户研究部分——如果你有做可用性测试的计划,可以加一节"4. 评估方法"\n4. 颜色编码系统部分写得很好,可以加一个视觉化的表格来展示颜色-类型映射\n\n需要我展开其中某一点吗?',
---
## 📊 核心发现
### 1. 市场规模与增长
2026 年 Q2 全球智能助手市场规模预计达到 **187 亿美元**,同比增长 **34.2%**。
主要驱动力:
- 企业级 AI 助手采纳率从 38% 提升至 **56%**
- 多模态能力推动使用场景扩展
- 开源模型降低了部署门槛
### 2. 竞争格局变化
| 厂商 | 份额 | 环比变化 | 核心优势 |
|------|------|---------|---------|
| OpenAI | 41% | +2.3% | 品牌 + 开发者生态 |
| Anthropic | 18% | **+5.1%** | 安全对齐 + 长上下文 |
| Google | 15% | -1.2% | 搜索整合 + 多模态 |
| Meta | 12% | +3.8% | 开源 + 成本优势 |
Anthropic 的增长最快(+5.1%),说明 **安全对齐** 正在成为关键竞争力。
### 3. 值得关注的趋势
- **可信度** 是用户选择助手的首要因素(47% 受访者提及)
- 企业用户对 \`system prompt\` 透明度的需求同比增长 **82%**
- 工具调用(Function Calling)使用率从 23% 增长到 51%
- 报告结语指出:**竞争正从模型能力转向体验设计**
---
需要我深入分析某个方面吗?点击文档的 **「查看解析」** 按钮可以看到 AI 提取的完整结构化内容。`,
}, },
], ],
timestamp: now - 60000, timestamp: now - 60000,
+280 -134
View File
@@ -1,13 +1,53 @@
/**
* Demo E — 日志分析(无文档传入)
*
* 场景:用户分享一段 Nginx 访问日志,请求 AI 助手帮忙分析
* 异常模式和潜在安全风险。
*
* 关键展示:
* 1. long_text 用于展示原始日志全文(折叠态仅显示前2行)
* 2. tool_call_request/result 展示日志分析工具的调用过程
* 3. static_var 注入服务器环境和分析参数
* 4. memory 记录用户的系统环境和分析偏好
* 5. 无 document/media 段 —— 突出"纯文本日志分析"场景
*/
import type { PromptEnvelope } from '../../types/protocol' import type { PromptEnvelope } from '../../types/protocol'
import { getSkills } from '../skills' import { getSkills } from '../skills'
const now = Date.now() const now = Date.now()
const sampleLog = `192.168.1.10 - - [07/Jun/2026:10:15:23 +0800] "GET /api/users HTTP/1.1" 200 1234 "-" "curl/7.88.1"
192.168.1.20 - - [07/Jun/2026:10:15:25 +0800] "POST /api/login HTTP/1.1" 302 0 "-" "Mozilla/5.0"
10.0.0.5 - - [07/Jun/2026:10:15:28 +0800] "GET /health HTTP/1.1" 200 2 "-" "Kubernetes/1.28"
192.168.1.10 - - [07/Jun/2026:10:16:01 +0800] "GET /api/orders HTTP/1.1" 200 8921 "-" "curl/7.88.1"
203.0.113.42 - - [07/Jun/2026:10:16:05 +0800] "GET /admin HTTP/1.1" 403 189 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:06 +0800] "GET /admin/config HTTP/1.1" 404 153 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:07 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:08 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:09 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:10 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:11 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
192.168.1.30 - - [07/Jun/2026:10:17:00 +0800] "GET /api/products?page=1 HTTP/1.1" 200 15420 "-" "Mozilla/5.0"
192.168.1.30 - - [07/Jun/2026:10:17:02 +0800] "GET /api/products?page=2 HTTP/1.1" 200 14893 "-" "Mozilla/5.0"
192.168.1.30 - - [07/Jun/2026:10:17:04 +0800] "GET /api/products?page=3 HTTP/1.1" 200 15102 "-" "Mozilla/5.0"
198.51.100.7 - - [07/Jun/2026:10:18:30 +0800] "GET / HTTP/1.1" 200 5678 "-" "Mozilla/5.0"
198.51.100.7 - - [07/Jun/2026:10:18:32 +0800] "GET /static/css/main.css HTTP/1.1" 200 28491 "-" "Mozilla/5.0"
198.51.100.7 - - [07/Jun/2026:10:18:33 +0800] "GET /static/js/app.js HTTP/1.1" 200 128034 "-" "Mozilla/5.0"
10.0.0.5 - - [07/Jun/2026:10:20:00 +0800] "GET /health HTTP/1.1" 200 2 "-" "Kubernetes/1.28"
192.168.1.10 - - [07/Jun/2026:10:21:15 +0800] "GET /api/users HTTP/1.1" 200 1234 "-" "curl/7.88.1"
192.168.1.10 - - [07/Jun/2026:10:21:16 +0800] "GET /api/orders HTTP/1.1" 200 8921 "-" "curl/7.88.1"
192.168.1.10 - - [07/Jun/2026:10:21:17 +0800] "GET /api/products HTTP/1.1" 200 15420 "-" "curl/7.88.1"
10.0.0.6 - - [07/Jun/2026:10:22:00 +0800] "GET /health HTTP/1.1" 503 57 "-" "Kubernetes/1.28"
10.0.0.6 - - [07/Jun/2026:10:22:05 +0800] "GET /health HTTP/1.1" 503 57 "-" "Kubernetes/1.28"
10.0.0.6 - - [07/Jun/2026:10:22:10 +0800] "GET /health HTTP/1.1" 503 57 "-" "Kubernetes/1.28"
10.0.0.6 - - [07/Jun/2026:10:22:15 +0800] "GET /health HTTP/1.1" 200 2 "-" "Kubernetes/1.28"`
export const demoE: PromptEnvelope = { export const demoE: PromptEnvelope = {
version: '1.0', version: '1.0',
model: 'claude-opus-4-8', model: 'claude-opus-4-8',
messages: [ messages: [
// --- System message: 加载 skills + memory + tools --- // --- System message ---
{ {
id: 'e-1', id: 'e-1',
role: 'system', role: 'system',
@@ -20,45 +60,56 @@ export const demoE: PromptEnvelope = {
}, },
{ {
kind: 'static_var', kind: 'static_var',
name: 'language', name: 'server_name',
value: '中文(简体)', value: 'production-api-01',
description: '模型回复的首选语言', description: '目标服务器名称',
}, },
{ {
kind: 'static_var', kind: 'static_var',
name: 'knowledge_cutoff', name: 'analysis_depth',
value: '2026年1月', value: '全面(异常检测 + 安全审计 + 性能分析)',
description: '模型训练数据截止日期', description: '日志分析的范围深度',
}, },
{ {
kind: 'system_prompt', kind: 'system_prompt',
content: `当前日期:{{current_date}} content: `当前日期:{{current_date}}
回复语言:{{language}} 目标服务器:{{server_name}}
知识截止:{{knowledge_cutoff}} 分析范围:{{analysis_depth}}
你是 HCI 课程设计助手,具备 Anthropic Skills 机制。 你是日志分析专家助手。你的核心能力:
你有以下 skills 可用。用户输入以 / 开头的命令时会直接触发对应 skill。你也可以在分析用户意图后,主动建议合适的 skill。 1. **异常检测** — 识别错误状态码(4xx/5xx)、请求突增、响应时间异常
2. **安全审计** — 发现暴力破解尝试、路径探测、SQL 注入尝试
3. **性能分析** — 统计端点响应分布、慢请求排查、热点资源识别
4. **趋势报告** — 按时间窗口聚合,生成可读性高的分析摘要
回复风格:简洁、有结构、给出可操作建议。`, 分析原则:
- 优先发现模式而非孤立事件
- 区分误报和真正的问题
- 每个发现标注严重等级和置信度
- 在工具调用中执行计算分析,回复中给出解读`,
collapsed: true, collapsed: true,
}, },
{ {
kind: 'memory', kind: 'memory',
description: description:
'以下是从过往对话中总结的关于你的信息,模型会参考这些记忆来个性化回复。', '以下是你对用户的了解,参考这些记录来提供个性化的日志分析服务。',
items: [ items: [
{ {
title: '用户背景', title: '用户身份',
content: '小明,设计系研二,HCI 方向。正在做课程设计,课题是 LLM 上下文透明性。', content: '小陈,后端开发工程师,负责生产环境的运维监控。',
}, },
{ {
title: '当前进度', title: '系统环境',
content: '已完成 MVP 开发(React + TypeScript 聊天界面),展示了 9 种 Segment 的差异化渲染。', content: 'Kubernetes 集群上的微服务架构,API 网关使用 Nginx。生产环境有三台节点。',
}, },
{ {
title: '关注点', title: '分析偏好',
content: '关心 Anthropic Skills 的渐进式披露机制能否作为 HCI 课程中的交互设计案例。', content: '偏好先看整体概览再深入细节。对安全相关告警特别敏感,需要高亮标注。',
},
{
title: '上次分析记录',
content: '上周分析过同一台服务器的日志,发现了一个定时任务导致的 503 抖动。',
}, },
], ],
collapsed: true, collapsed: true,
@@ -66,190 +117,285 @@ export const demoE: PromptEnvelope = {
{ {
kind: 'skills', kind: 'skills',
description: description:
'Skills 是模型可调用的内置能力。输入 / 触发,或根据对话上下文由 Agent 自动判断并调用。当前可用以下 skills', '以下是可用的技能助手,通过 /skill_name 触发',
items: getSkills(['deep-research', 'code-review', 'verify', 'simplify', 'loop']), items: getSkills(['summarize', 'qa', 'translate']),
collapsed: true, collapsed: true,
}, },
{ {
kind: 'tool_overview', kind: 'tool_overview',
items: [ items: [
{ {
name: 'run_skill', name: 'run_code',
description: '执行一个 Skillslash command', description: '在沙箱中执行 Python/Shell 代码进行日志解析和统计',
parameters: 'skill_name: string, input: string', parameters: 'language: string, code: string',
schema: { schema: {
type: 'object', type: 'object',
properties: { properties: {
skill_name: { type: 'string', description: 'Skill 名称' }, language: { type: 'string', enum: ['python', 'bash'], description: '执行语言' },
input: { type: 'string', description: '传递给 skill 的用户输入' }, code: { type: 'string', description: '要执行的代码' },
}, },
required: ['skill_name', 'input'], required: ['language', 'code'],
},
},
{
name: 'search_knowledge',
description: '搜索已知的漏洞模式和安全公告',
parameters: 'query: string',
schema: {
type: 'object',
properties: {
query: { type: 'string', description: '搜索关键词' },
},
required: ['query'],
}, },
}, },
], ],
collapsed: true, collapsed: true,
}, },
], ],
timestamp: now - 360000, timestamp: now - 600000,
}, },
// --- User message: 触发 research 需求 --- // --- User 请求日志分析 ---
{ {
id: 'e-2', id: 'e-2',
role: 'user', role: 'user',
segments: [ segments: [
{ {
kind: 'text', kind: 'text',
content: '我想深入了解 Anthropic Skills 的渐进式披露机制(Progressive Disclosure),作为我的 HCI 课程论文的案例研究对象。请帮我调研一下这个机制的设计原理、交互模式和学术界相关讨论。', content: '生产环境 API 服务器刚刚的访问日志,帮我看一下有没有异常。我自己扫了一遍,感觉有几个可疑的 IP 在尝试访问 /admin 路径,但不太确定是不是误报。另外 /health 端点偶尔返回 503 的情况也需要你分析一下。',
},
{
kind: 'long_text',
content: sampleLog,
charCount: sampleLog.length,
collapsed: true,
}, },
], ],
timestamp: now - 300000, timestamp: now - 500000,
}, },
// --- Assistant: 判断需要 research,主动触发 /deep-research --- // --- Assistant 初始分析回复 ---
{ {
id: 'e-3', id: 'e-3',
role: 'assistant', role: 'assistant',
segments: [ segments: [
{ {
kind: 'text', kind: 'text',
content: `你的课程论文选题很棒!Anthropic Skills 的渐进式披露机制确实是一个很好的 HCI 案例分析对象——它以 **三阶段信息展开**(overview → detail → full instructions)来降低认知负荷,同时保持功能的可发现性。 content: `我来分析这份日志。先快速概览一下整体情况:
让我用 \`/deep-research\` skill 做一个系统性调研:`, 从格式看是标准的 Nginx combined 格式,时间窗口约 **10:1510:22**(约 7 分钟),共 **25 条**请求记录。几家不同的客户端:
- **192.168.1.10** — 内部 API 调用(curl
- **192.168.1.20** — 正常浏览器登录
- **10.0.0.5** — K8s 健康检查
- **192.168.1.30** — 浏览器浏览商品页面
- **198.51.100.7** — 正常用户访问首页
- **10.0.0.6** — 另一台节点的健康检查
- **203.0.113.42** — ⚠️ 可疑 IP
我先用 \`run_code\` 对请求做聚合统计,确认模式后再深入分析可疑流量。`,
}, },
{ {
kind: 'tool_call_request', kind: 'tool_call_request',
toolName: 'run_skill', toolName: 'run_code',
arguments: { arguments: {
skill_name: 'deep-research', language: 'python',
input: 'Anthropic Skills progressive disclosure mechanism — design principles, interaction patterns, HCI academic discussions, related concepts (progressive disclosure in UX, Nielsen\'s heuristics, information architecture patterns for AI interfaces)', code: `from collections import Counter, defaultdict
import re
log_text = """192.168.1.10 - - [07/Jun/2026:10:15:23 +0800] "GET /api/users HTTP/1.1" 200 1234 "-" "curl/7.88.1"
192.168.1.20 - - [07/Jun/2026:10:15:25 +0800] "POST /api/login HTTP/1.1" 302 0 "-" "Mozilla/5.0"
10.0.0.5 - - [07/Jun/2026:10:15:28 +0800] "GET /health HTTP/1.1" 200 2 "-" "Kubernetes/1.28"
192.168.1.10 - - [07/Jun/2026:10:16:01 +0800] "GET /api/orders HTTP/1.1" 200 8921 "-" "curl/7.88.1"
203.0.113.42 - - [07/Jun/2026:10:16:05 +0800] "GET /admin HTTP/1.1" 403 189 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:06 +0800] "GET /admin/config HTTP/1.1" 404 153 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:07 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:08 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:09 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:10 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
203.0.113.42 - - [07/Jun/2026:10:16:11 +0800] "POST /admin/login HTTP/1.1" 401 198 "-" "python-requests/2.31.0"
192.168.1.30 - - [07/Jun/2026:10:17:00 +0800] "GET /api/products?page=1 HTTP/1.1" 200 15420 "-" "Mozilla/5.0"
192.168.1.30 - - [07/Jun/2026:10:17:02 +0800] "GET /api/products?page=2 HTTP/1.1" 200 14893 "-" "Mozilla/5.0"
192.168.1.30 - - [07/Jun/2026:10:17:04 +0800] "GET /api/products?page=3 HTTP/1.1" 200 15102 "-" "Mozilla/5.0"
198.51.100.7 - - [07/Jun/2026:10:18:30 +0800] "GET / HTTP/1.1" 200 5678 "-" "Mozilla/5.0"
198.51.100.7 - - [07/Jun/2026:10:18:32 +0800] "GET /static/css/main.css HTTP/1.1" 200 28491 "-" "Mozilla/5.0"
198.51.100.7 - - [07/Jun/2026:10:18:33 +0800] "GET /static/js/app.js HTTP/1.1" 200 128034 "-" "Mozilla/5.0"
10.0.0.5 - - [07/Jun/2026:10:20:00 +0800] "GET /health HTTP/1.1" 200 2 "-" "Kubernetes/1.28"
192.168.1.10 - - [07/Jun/2026:10:21:15 +0800] "GET /api/users HTTP/1.1" 200 1234 "-" "curl/7.88.1"
192.168.1.10 - - [07/Jun/2026:10:21:16 +0800] "GET /api/orders HTTP/1.1" 200 8921 "-" "curl/7.88.1"
192.168.1.10 - - [07/Jun/2026:10:21:17 +0800] "GET /api/products HTTP/1.1" 200 15420 "-" "curl/7.88.1"
10.0.0.6 - - [07/Jun/2026:10:22:00 +0800] "GET /health HTTP/1.1" 503 57 "-" "Kubernetes/1.28"
10.0.0.6 - - [07/Jun/2026:10:22:05 +0800] "GET /health HTTP/1.1" 503 57 "-" "Kubernetes/1.28"
10.0.0.6 - - [07/Jun/2026:10:22:10 +0800] "GET /health HTTP/1.1" 503 57 "-" "Kubernetes/1.28"
10.0.0.6 - - [07/Jun/2026:10:22:15 +0800] "GET /health HTTP/1.1" 200 2 "-" "Kubernetes/1.28"""
# 解析日志
pattern = r'(\\S+) - - \\[(.+?)\\] "(.+?)" (\\d+) (\\d+) ".*?" "(.*?)"'
records = []
for line in log_text.strip().split('\\n'):
m = re.match(pattern, line)
if m:
records.append({
'ip': m.group(1),
'time': m.group(2),
'request': m.group(3),
'status': int(m.group(4)),
'size': int(m.group(5)),
'ua': m.group(6)
})
# 1. IP 统计
print("=== 按 IP 请求量统计 ===")
ip_counter = Counter(r['ip'] for r in records)
for ip, count in ip_counter.most_common():
print(f" {ip:20s} → {count} 次请求")
# 2. 状态码分布
print("\\n=== 状态码分布 ===")
status_counter = Counter(r['status'] for r in records)
for code, count in sorted(status_counter.items()):
print(f" {code} → {count} 次")
# 3. 可疑 IP 分析
print("\\n=== 可疑 IP: 203.0.113.42 的请求序列 ===")
for r in records:
if r['ip'] == '203.0.113.42':
print(f" [{r['time']}] {r['request']} → {r['status']}")
# 4. /health 端点分析
print("\\n=== /health 端点状态 ===")
for r in records:
if '/health' in r['request']:
print(f" {r['ip']:15s} [{r['time']}] → {r['status']} (UA: {r['ua']})")
# 5. 非 2xx 占比
total = len(records)
errors = sum(1 for r in records if r['status'] >= 400)
print(f"\\n=== 总结 ===")
print(f" 总请求数: {total}")
print(f" 错误请求: {errors} ({errors/total*100:.1f}%)")
print(f" 正常请求: {total - errors} ({(total-errors)/total*100:.1f}%)")`,
}, },
collapsed: false, collapsed: false,
}, },
], ],
timestamp: now - 280000, timestamp: now - 480000,
}, },
// --- Skill 触发:指令以 tool_call_result 形式追加到对话 --- // --- Tool 调用结果 ---
{ {
id: 'e-4', id: 'e-4',
role: 'assistant', role: 'assistant',
segments: [ segments: [
{ {
kind: 'tool_call_result', kind: 'tool_call_result',
toolName: 'run_skill', toolName: 'run_code',
success: true, success: true,
result: `[/deep-research 已触发] result: `=== 按 IP 请求量统计 ===
192.168.1.10 → 5 次请求
203.0.113.42 → 7 次请求
198.51.100.7 → 3 次请求
10.0.0.5 → 2 次请求
10.0.0.6 → 4 次请求
192.168.1.20 → 1 次请求
192.168.1.30 → 3 次请求
深度研究工作流程: === 状态码分布 ===
1. 分析用户问题,拆解为 3-5 个子问题 200 → 14 次
2. 对每个子问题执行多源搜索(学术 + 行业 + 新闻) 302 → 1 次
3. 抓取高相关性页面全文 401 → 5 次
4. 交叉验证:至少两个独立来源确认同一关键事实 403 → 1 次
5. 生成报告格式:摘要 → 分项发现 → 证据表 → 限定说明 404 → 1 次
6. 每声明标注来源和可信度评级`, 503 → 3 次
collapsed: true,
=== 可疑 IP: 203.0.113.42 的请求序列 ===
[07/Jun/2026:10:16:05 +0800] GET /admin → 403
[07/Jun/2026:10:16:06 +0800] GET /admin/config → 404
[07/Jun/2026:10:16:07 +0800] POST /admin/login → 401
[07/Jun/2026:10:16:08 +0800] POST /admin/login → 401
[07/Jun/2026:10:16:09 +0800] POST /admin/login → 401
[07/Jun/2026:10:16:10 +0800] POST /admin/login → 401
[07/Jun/2026:10:16:11 +0800] POST /admin/login → 401
=== /health 端点状态 ===
10.0.0.5 [07/Jun/2026:10:15:28 +0800] → 200 (UA: Kubernetes/1.28)
10.0.0.5 [07/Jun/2026:10:20:00 +0800] → 200 (UA: Kubernetes/1.28)
10.0.0.6 [07/Jun/2026:10:22:00 +0800] → 503 (UA: Kubernetes/1.28)
10.0.0.6 [07/Jun/2026:10:22:05 +0800] → 503 (UA: Kubernetes/1.28)
10.0.0.6 [07/Jun/2026:10:22:10 +0800] → 503 (UA: Kubernetes/1.28)
10.0.0.6 [07/Jun/2026:10:22:15 +0800] → 503 (UA: Kubernetes/1.28)
=== 总结 ===
总请求数: 25
错误请求: 10 (40.0%)
非 2xx 响应占比高达 40%,
主要集中在两个异常模式上。`,
collapsed: false,
}, },
], ],
timestamp: now - 270000, timestamp: now - 460000,
}, },
// --- Skill execution result --- // --- Assistant 综合报告 ---
{ {
id: 'e-5', id: 'e-5',
role: 'assistant', role: 'assistant',
segments: [
{
kind: 'tool_call_result',
toolName: 'run_skill',
success: true,
result: `[/deep-research] 执行完成 · 搜索 12 个来源 · 抓取 8 篇全文 · 交叉验证通过
## 摘要
Anthropic Skills 的渐进式披露机制是一种三层信息架构,专门为 AI 代理的可扩展功能系统设计。核心思想:"仅在用户需要时才展示细节",与 Nielsen 的经典可用性原则高度一致。
## 分项发现
### 1. 三层披露模型
| 层次 | 内容 | 触发时机 |
|------|------|---------|
| L1 概览 | 名称 + 一句话描述 | 始终可见(skills 面板) |
| L2 详情 | 功能说明 + 触发条件 + 参数 | 用户点击展开 |
| L3 指令 | 完整 system prompt 正文 | 用户再次点击"查看注入指令" |
**设计原理**:这是 "information on demand" 模式的实现——信息存在但不喧嚣。L1 提供识别(recognition),L2 提供评估(evaluation),L3 提供理解(understanding)。
### 2. 与经典 HCI 理论的对应
- **Nielsen 的 Flexibility & Efficiency heuristics**L1 满足新手(可识别),L3 满足专家(可审阅)
- **Shneiderman 的 Visual Information Seeking Mantra**"Overview first, zoom and filter, then details-on-demand"——三层模型完美映射到 overview → zoom → details 流程
- **Cognitive Load Theory (Sweller)**L1 层只占用工作记忆的极小空间,L2/L3 按需加载
### 3. 与其他 AI 产品的对比
- **OpenAI GPTs**:配置页是扁平表单,缺乏渐进式展开 → 认知负荷高
- **Gemini Gems**:类似 GPTs,所有配置信息同时可见
- **Anthropic Skills**:三层的文件系统式浏览——/ 触发、描述预览、then 深入
### 4. 交互模式创新
Skills 采用了 **slash command + 自然语言** 的双模触发:
- 显式触发:用户输入 \`/skill-name\`
- 隐式触发:Agent 根据对话上下文判断并建议使用 skill
这在 HCI 上称为 "mixed-initiative interaction"。
### 5. 学术相关文献
1. "Progressive Disclosure in Mobile UI" (CHI 2016) — 实验证明渐进式展开减少 37% 的错误操作
2. "Designing for Mixed-Initiative Interaction" (TOCHI 2020) — Agent 主动建议 vs 用户显式触发的用户偏好研究
3. "Information Scent in AI Interfaces" (CSCW 2024) — 讨论了 skills 描述如何帮助用户形成"信息气味"
## 证据表
| 声明 | 来源 | 可信度 |
|------|------|--------|
| 三层披露模型 | Anthropic Agent SDK 文档 | ★★★★★ |
| 37% 错误减少 | CHI 2016 实验 | ★★★★ |
| Mixed-initiative | TOCHI 2020 | ★★★★ |
## 限定说明
Anthropic Skills 机制仍在快速迭代中。上述分析基于 2026 年 6 月的公开文档和代码。建议在论文中标注版本时间。`,
collapsed: false,
},
],
timestamp: now - 260000,
},
// --- Assistant: 综合报告 ---
{
id: 'e-6',
role: 'assistant',
segments: [ segments: [
{ {
kind: 'text', kind: 'text',
content: `## 调研结论 content: `## 日志分析报告
基于 \`/deep-research\` 的交叉验证结果,我建议你的论文从以下角度分析 Skills 渐进式披露: ### 🔴 高危:暴力破解尝试
### 🎯 最佳分析框架 **IP: 203.0.113.42**(来源:外部,UA: python-requests
**Shneiderman 的 "Overview first, zoom and filter, then details-on-demand"** 是最贴切的理论框架——Skills 的三层模型几乎是对这个 mantra 的精确工程实现。 在 **10:16:0510:16:11** 的 6 秒内向 /admin 路径连续发送了 **7 次请求**,典型的暴力破解模式:
### 📐 可量化的 HCI 指标 | 时间 | 请求 | 状态 | 说明 |
|------|------|------|------|
| +0s | GET /admin | 403 | 探路——发现 /admin 存在 |
| +1s | GET /admin/config | 404 | 试图访问敏感配置 |
| +2~6s | POST /admin/login ×5 | 401 | 连续尝试登录——5 次均失败 |
1. **信息可发现性**:L1 概览层——用户能否快速识别需要的 skillrecognition over recall **建议措施:**
2. **认知负荷**:对比"全量展示"vs"渐进式披露"的工作记忆占用 - 🔒 立即对该 IP 加入 WAF 黑名单
3. **操作效率**slash command 显式触发 vs Agent 隐式建议的完成时间对比 - 📋 检查 fail2ban 或类似自动封禁机制是否正常运行
- 🚨 确认 admin 端点的访问控制策略(当前 403 正确拦截,但暴力破解仍消耗服务器资源)
### 🔗 建议引用的关键文献 ---
- CHI 2016 的渐进式披露实验(有量化数据支持你的设计论点) ### 🟡 中危:/health 端点间歇 503
- TOCHI 2020 的 mixed-initiative 研究(对应双模触发机制)
- Anthropic 2025 的 Skills Architecture RFC(一手来源)
需要我帮你生成论文的文献综述部分吗?`, **节点 10.0.0.6** 在 **10:22:0010:22:10** 的 10 秒内连续返回 503,随后恢复 200。而 **10.0.0.5** 一直正常。
这与上周分析中定时任务导致的 503 抖动模式一致。建议检查该节点上是否在整点前后有定时任务(如日志轮转、缓存预热等)。
**建议措施:**
- ⏰ 检查 10.0.0.6 的 cron 配置
- 📊 添加更细粒度的 /health 监控(响应耗时 + 组件健康分别上报)
- 🔄 考虑滚动重启使两个节点的健康检查窗口错开
---
### 🟢 常规观察
- **192.168.1.10** — 内部 API 客户端,访问模式正常(用户/订单/商品查询)
- **192.168.1.20** — 一次正常登录(POST /api/login → 302 重定向)
- **198.51.100.7** — 正常用户访问,加载了首页 + CSS + JS
- **192.168.1.30** — 分页浏览商品,行为正常
- 无性能异常(无超时记录或慢请求)
---
### 📋 总结优先级
| 优先级 | 问题 | 影响 |
|--------|------|------|
| P0 | 203.0.113.42 暴力破解 | 安全风险,立即封禁 |
| P1 | 10.0.0.6 间歇 503 | 稳定性风险,排查定时任务 |
| P3 | 整体 40% 非 2xx | 排除以上两者后正常 |
需要我进一步分析某个方面吗?比如用 search_knowledge 查询 203.0.113.42 是否在已知攻击数据库中出现过?`,
}, },
], ],
timestamp: now - 240000, timestamp: now - 420000,
}, },
], ],
} }
+1
View File
@@ -132,6 +132,7 @@ export interface DocumentSegment {
mimeType: string mimeType: string
snippet: string // 前 200 字符预览 snippet: string // 前 200 字符预览
sizeBytes: number sizeBytes: number
parsedContent?: string // 解析后的完整文本内容(点击"查看解析"时展示)
} }
export interface LongTextSegment { export interface LongTextSegment {