Agent 在生成代码时,必须严格基于以下技术栈及版本约束:
- Flutter SDK:
^3.22.0(或当前 2026 年稳定版) - 状态管理:
flutter_riverpod+riverpod_annotation(强类型、编译期安全) - 本地缓存:
shared_preferences(Flutter 官方本地键值缓存,持久化人设) - OCR 引擎:
flutter_ocr_native(Web:Tesseract.js) - 网络请求:
dio(支持拦截器,用于对接大模型 API) - 目标平台: Web
Agent 须在 lib/data/models/ 目录下生成以下 Dart 模型:
class Persona {
final int id;
final String name; // 人设名称,如“职场太极大师”
final String description; // 用户可见的人设描述
final String systemPrompt; // 核心 Prompt 约束
final List<String> tags; // 标签,如 ['Work', 'Humor']
final DateTime createdAt;
const Persona({
required this.id,
required this.name,
required this.description,
required this.systemPrompt,
required this.tags,
required this.createdAt,
});
}enum MessageSender { peer, me, unknown }
class ChatMessageSlice {
final String text;
final MessageSender sender;
final double timestampY; // 用于截图排序的 Y 轴坐标
ChatMessageSlice({
required this.text,
required this.sender,
required this.timestampY,
});
}
请 Agent 按照以下规范初始化项目骨架:
lib/
├── main.dart
├── core/
│ ├── constants/ # API 密钥配置及 Prompt 模板
│ ├── theme/ # 极简 UI 主题
│ └── utils/ # 剪贴板监听器、图片选择器封装
├── data/
│ ├── database/ # SharedPreferences 本地缓存
│ ├── models/ # 实体模型 (Persona)
│ └── services/ # LLM API 服务、Google ML Kit OCR 服务
├── providers/ # Riverpod 状态提供者 (PersonaNotifier, ChatNotifier)
└── ui/
├── home/ # 主界面(人设管理)
├── chat_assistant/ # 回复生成交互面板(支持输入文本或导入截图)
└── widgets/ # 通用轻量组件(回复卡片、加载动画)
Agent 需实现一个常驻的后台或生命周期内监听器。当应用前台唤醒或检测到剪贴板变动时,自动将内容填充至分析队列。
// lib/core/utils/clipboard_helper.dart
import 'package:flutter/services.dart';
class ClipboardHelper {
static Future<String?> getLatestText() async {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) {
// 过滤掉空白字符或过长文本(大于500字通常非单句聊天记录)
final cleanText = data.text!.trim();
if (cleanText.isNotEmpty && cleanText.length < 500) {
return cleanText;
}
}
return null;
}
}
在处理图片识别时,Agent 必须通过 bounding box 的相对 peer,右侧为 me)。
// lib/data/services/ocr_service.dart
import 'dart:typed_data';
import 'package:flutter_ocr_native/flutter_ocr_native.dart';
import '../models/chat_context.dart';
class OcrService {
final OcrReader _reader = OcrReader();
Future<List<ChatMessageSlice>> processChatScreenshot(Uint8List imageBytes) async {
await _reader.setLanguage(OcrLanguage.chineseSimplified);
// Web 需使用 readFromBytes
final OcrResult result = await _reader.readFromBytes(imageBytes);
List<ChatMessageSlice> slices = [];
// 假设标准屏幕宽度(用于计算左右边界比例)
// 实际生产中可结合图片元数据图片的 width 进行比例划分
// 通常:X 轴起始点在左侧 0%~60% 区间且长度不超过一定比例的为对方;靠右侧的为自己。
for (TextBlock block in result.blocks) {
for (TextLine line in block.lines) {
final double x = line.boundingBox.left;
final double y = line.boundingBox.top;
MessageSender sender = MessageSender.unknown;
// 简易动态阈值算法:根据 X 轴坐标判定角色
if (x < 300) {
sender = MessageSender.peer;
} else {
sender = MessageSender.me;
}
slices.add(ChatMessageSlice(
text: line.text,
sender: sender,
timestampY: y,
));
}
}
// 极其重要:基于 Y 轴从上到下严格排序,恢复聊天时间线
slices.sort((a, b) => a.timestampY.compareTo(b.timestampY));
return slices;
}
Future<void> dispose() => _reader.dispose();
}Agent 必须内置以下通用模板,保证大模型能够稳定输出结构化的 3 种回复:
// lib/core/constants/prompt_templates.dart
class PromptTemplates {
static String buildSystemPrompt(String personaInstruction) {
return '''
你是一个智能聊天助手。你的核心任务是帮用户回复社交软件上的消息。
你当前扮演的角色设定如下:
$personaInstruction
请严格遵守以下规则:
1. 分析用户输入的聊天上下文(可能是单句话,也可能是按时间排序的多句对话)。
2. 基于你的角色设定,生成 3 个不同维度的回复选项。
3. 请严格按照给定的 JSON 格式输出,不要包含任何 markdown 标记(如 ```json)或任何额外的解释性文字。
期望的输出格式(JSON):
{
"options": [
{"label": "选项一简短意图描述", "text": "具体回复的文字内容"},
{"label": "选项二简短意图描述", "text": "具体回复的文字内容"},
{"label": "选项三简短意图描述", "text": "具体回复的文字内容"}
]
}
''';
}
}
Agent 需要在 lib/ui/ 下实现两个核心页面:
- HomeScreen (人设管理中心):
- 主列表采用
ListView.builder渲染本地缓存中读取的Persona列表。 - 提供全局浮动操作按钮(FAB)用于快速添加自定义 System Prompt。
- ChatAssistantScreen (回复生成面板):
- 顶部输入框:默认自动读取并展示
ClipboardHelper.getLatestText()的内容。 - 快捷按钮栏:提供
[导入截图识别]按钮,触发image_picker选择图片后,交由OcrService处理,处理后以列表形式在界面上预览被提取出的上下文。 - 底部结果区:展示 AI 生成的 3 个选项卡片。点击任意卡片,触发
Clipboard.setData将文本写回剪贴板,并调用ScaffoldMessenger弹出 Toast 提示用户“已复制,快去粘贴吧!”。
在完成代码生成后,Agent 需自我运行以下断言:
- 所有对文本处理的代码均无 bare
<或>符号,防止编译期布局解析错误。 - 在
OcrService结束时已正确调用OcrReader.dispose(),无内存泄漏隐患。 - 网络层 Dio 请求已配置
connectTimeout与receiveTimeout(推荐 15 秒限制)。