Dexter 全面解读:从零到一的 AI 研究代理平台(含架构设计、工具生态与扩展开发)
posts posts 2026-03-26T16:15:00+08:00系统学习 Dexter 项目全部中文文档,涵盖:多模型路由、金融工具链、网页工具、技能系统、持久记忆、WhatsApp 网关、心跳与定时任务、Agent 循环机制、扩展开发与故障排查的完整技术指南。技术笔记AI, Agent, Dexter, 金融工具, 多模型路由, 研究代理, 自动化难度:⭐⭐⭐⭐ | 类型:专家设计 | 预计阅读时间:60 分钟 目标读者:AI 开发者、金融科技研究者、想在本地搭建 Agent 系统的用户
🎯 概述:Dexter 不只是一个聊天机器人
当你第一次看到 Dexter 的介绍时,你可能会想:“又一个 CLI 聊天工具?”
不。Dexter 的野心比这大得多。
Dexter 是香港大学开发的一个运行在终端的 AI 研究代理平台。
它的目标非常清晰:不是生成「看起来像答案」的文本,而是把你的问题转成一组研究动作,再调用金融、网页、文件、技能、记忆等工具完成任务。
这意味着 Dexter 的价值不在于「会聊天」,而在于「会做研究」。
📊 能力全景图
Dexter 的能力可以分成 8 大系统:
| # | 系统 | 核心能力 | 代表工具 |
|---|---|---|---|
| 1 | 多模型路由 | 8家提供商统一接入 | OpenAI、Anthropic、Google、xAI、Moonshot、DeepSeek、OpenRouter、Ollama |
| 2 | 金融工具链 | 财报、价格、新闻、筛选 | get_financials、get_market_data、read_filings、stock_screener |
| 3 | 网页工具 | 搜索、抓取、渲染 | web_search、web_fetch、browser |
| 4 | 文件系统 | 本地文件读写编辑 | read_file、write_file、edit_file |
| 5 | 技能系统 | 可复用工作流 | skill(调用 SKILL.md) |
| 6 | 持久记忆 | 跨会话知识积累 | memory_search、memory_get、memory_update |
| 7 | WhatsApp 网关 | 消息通道接入 | Self-chat、Bot phone、群聊 |
| 8 | 自动化引擎 | 心跳监控 + 定时任务 | heartbeat、cron |
🏛️ 系统架构:六层协同设计
分层总览
┌─────────────────────────────────────────────────────────────┐
│ 入口层 │
│ src/index.tsx、src/gateway/index.ts │
├─────────────────────────────────────────────────────────────┤
│ 交互层 │
│ CLI 终端 UI、输入历史、状态显示 │
├─────────────────────────────────────────────────────────────┤
│ 代理层 │
│ 规划、迭代执行、上下文管理、工具协同 │
├─────────────────────────────────────────────────────────────┤
│ 模型层 │
│ 多提供商适配、调用路由、重试策略 │
├─────────────────────────────────────────────────────────────┤
│ 工具层 │
│ 金融工具、网页工具、文件工具、自动化工具、记忆工具 │
├─────────────────────────────────────────────────────────────┤
│ 扩展能力层 │
│ 技能系统、记忆系统、网关系统、调度系统 │
└─────────────────────────────────────────────────────────────┘为什么分层设计很重要?
| 问题现象 | 问题本质 |
|---|---|
| 模型回答差 | 不一定是模型问题,可能是工具没装配成功 |
| 网关收不到消息 | 不一定是网关问题,可能是调度没触发 |
| 记忆不生效 | 不一定是记忆问题,可能是初始化失败或检索条件不匹配 |
理解架构的目的不是“背目录”,而是知道一个问题最可能属于哪一层。
各层职责
| 层 | 核心职责 | 关键文件 |
|---|---|---|
| 入口层 | 进程启动、模式选择(CLI/Gateway) | src/index.tsx、src/gateway/ |
| 交互层 | 终端 UI、用户输入、历史管理 | src/cli.ts、src/components/ |
| 代理层 | 规划、迭代、上下文控制 | src/agent/agent.ts、scratchpad.ts |
| 模型层 | 提供商路由、LLM 调用 | src/model/llm.ts、src/providers.ts |
| 工具层 | 工具注册、条件装配 | src/tools/registry.ts |
| 扩展层 | 技能、记忆、网关、调度 | src/skills/、src/memory/ |
🤖 模型层:多模型统一路由架构
支持的 8 家提供商
| 提供商 | 模型前缀 | API Key 环境变量 |
|---|---|---|
| OpenAI | 无前缀,如 gpt-5.4 | OPENAI_API_KEY |
| Anthropic | claude- | ANTHROPIC_API_KEY |
gemini- | GOOGLE_API_KEY | |
| xAI | grok- | XAI_API_KEY |
| Moonshot | kimi- | MOONSHOT_API_KEY |
| DeepSeek | deepseek- | DEEPSEEK_API_KEY |
| OpenRouter | openrouter: | OPENROUTER_API_KEY |
| Ollama | ollama: | 不需要(本地) |
前缀路由机制
Dexter 根据模型名字自动推断提供商,无需额外配置层。这种设计让模型切换只需要改一个字符串。
Anthropic 的 Prompt Caching
对 Anthropic 模型,系统提示会被标记为 cache_control: ephemeral,显著降低重复输入成本——因为系统提示很长(工具描述、技能元数据、记忆信息、频道约束),缓存优化很有价值。
🔧 工具层:六类工具协同
Dexter 的工具可以分为 6 大类:
| 类别 | 工具 | 主要用途 |
|---|---|---|
| 金融研究 | get_financials、get_market_data、read_filings、stock_screener | 财务、价格、新闻、申报、筛选 |
| 网页浏览 | web_search、web_fetch、browser | 搜索、抓取、JavaScript 渲染 |
| 文件系统 | read_file、write_file、edit_file | 本地文件读写 |
| 自动化 | heartbeat、cron | 持续检查和定时任务 |
| 记忆 | memory_search、memory_get、memory_update | 持久记忆与会话回溯 |
| 技能 | skill | 调用 SKILL.md 工作流 |
金融工具的精细分工
| 工具 | 职责 | 典型问题 |
|---|---|---|
get_financials | 财务指标、估值、分析师预期 | 营收、利润、现金流、DCF |
get_market_data | 价格、新闻、内幕交易 | 股价涨跌、实时行情 |
read_filings | SEC 文件原文 | 10-K、10-Q、8-K 深度研究 |
stock_screener | 按条件筛选股票 | 找符合条件的标的 |
网页工具的选型原则
| 工具 | 成本 | 使用场景 |
|---|---|---|
web_search | 低 | 通用信息查找 |
web_fetch | 中 | 静态页面正文抓取 |
browser | 高 | JavaScript 渲染、单页应用 |
关键原则:不默认使用 browser。Dexter 的系统提示明确要求仅在必要时使用。
条件装配机制
Dexter 只把「当前真的能用」的工具暴露给模型。例如:
- 有
EXASEARCH_API_KEY→ 启用 Exa 版web_search - 无 Exa 但有
PERPLEXITY_API_KEY→ 启用 Perplexity 回退 - 有
X_BEARER_TOKEN→ 启用x_search
为什么这样设计? 如果系统提示列出不可调用的工具,模型会产生错误规划——用户体验比「压根不展示这个工具」更差。
🧠 技能系统:可复用工作流引擎
技能 vs 工具:职责划分
| 类型 | 提供什么 | 例子 |
|---|---|---|
| 工具 | 动作 | 查询财务数据、抓取网页 |
| 技能 | 方法 | DCF 估值流程、系统化研究模板 |
技能系统工作原理
1. 发现 → 扫描包含 SKILL.md 的目录
2. 暴露 → 仅注入技能名称和描述到系统提示
3. 按需 → Agent 匹配后调用 skill 工具
4. 执行 → 返回技能正文,解析相对路径为什么只暴露元数据?
大多数查询不需要技能。把所有技能全文塞进系统提示只会增加上下文成本,而没有实际收益。
内建技能示例
dcf:DCF 估值工作流x-research:系统化研究模板
💾 记忆系统:跨越会话的知识积累
三种上下文,不要混为一谈
| 概念 | 作用域 | 用途 |
|---|---|---|
| Scratchpad | 当前查询内 | 工具结果、思考轨迹 |
| 会话历史 | 当前 CLI 运行期间 | 多轮对话上下文 |
| 持久记忆 | 跨会话 | 用户偏好、长期信息 |
混合检索机制
记忆系统结合了:
- 向量检索:语义相似度匹配
- 文本检索:关键词精确匹配
- 时间衰减:优先返回新信息
- MMR 去冗余:避免重复上下文
为什么不用普通文件操作?
记忆不仅是文件写入,还涉及索引、检索语义和系统约定。绕过专用工具会破坏这一层抽象。
📱 WhatsApp 网关:从本地 CLI 到消息通道
三种使用模式
| 模式 | 特点 | 适用场景 |
|---|---|---|
| Self-chat | 给自己发消息 | 个人快速使用,上手最快 |
| Bot phone | 专用 Bot 号码 | 固定用户群,需配置 allowFrom |
| 群聊 | @ 提及触发 | 团队协作,必须用 @ 提及 |
安全策略
| 策略 | 含义 |
|---|---|
pairing | 需要配对 |
allowlist | 仅白名单可触发 |
open | 开放 |
disabled | 禁用 |
凭据存储
WhatsApp 凭据保存在 .dexter/credentials/whatsapp/<account>/,不应提交到 Git。
群聊为什么必须 @ 提及?
在群聊里,Dexter 必须通过 @ 提及才会响应。这不是技术限制,而是必要的噪音控制:如果机器人对所有消息都自动响应,误触发会很快失控。
⏰ 自动化层:心跳与定时任务
Heartbeat:清单驱动的长期监控
Heartbeat 读取 .dexter/HEARTBEAT.md 清单,按周期巡检。
适合场景:
- 固定关注标的
- 市场异动巡检
- 每日例行检查
Cron:调度驱动的通用任务
支持三种调度方式:
// 一次性时间点
{ "kind": "at", "at": "2026-04-01T14:00:00Z" }
// 固定间隔
{ "kind": "every", "everyMs": 3600000 }
// Cron 表达式
{ "kind": "cron", "expr": "0 9 * * 1-5", "tz": "America/New_York" }Fulfillment 模式
| 模式 | 行为 |
|---|---|
keep | 触发后继续保留,适合长期监控 |
once | 触发一次后自动停用,适合价格提醒 |
ask | 触发后询问用户是否继续 |
为什么自动化问题要先查网关?
Heartbeat 和 Cron 触发后,结果通常要通过网关回传给用户。所以当“任务似乎执行了,但就是没提醒”时,优先检查网关可用性,往往比先怀疑调度逻辑更高效。
🔄 Agent 循环:核心执行机制
完整执行路径
用户输入 → CLI 接收 → Agent.create() 初始化
↓
构建系统提示(工具 + SOUL.md + 记忆 + 技能元数据)
↓
模型生成响应 → 判断是否有工具调用
↓
执行工具 → 结果写入 scratchpad
↓
上下文超限?→ 触发清理(先清最早工具结果)
↓
更高压力?→ 触发 memory flush
↓
收敛后生成最终答案 → 返回给用户Scratchpad 的双重角色
- 调试资产:以 JSONL 形式记录完整执行轨迹,可回放
- 运行时资产:作为下一轮 prompt 的事实底座
上下文控制策略
Dexter 不是无限上下文。采用两层退让机制:
- 第一层:清理最早的工具结果,保留最近的
- 第二层:触发 memory flush,把部分内容迁移到记忆层
Tool Limit 的软边界设计
当工具调用即将超限时,Scratchpad.canCallTool() 会发出警告而不是硬阻断。
为什么不硬拦? 在代理系统里,完全硬编码的阻断规则会损失弹性。问题不在「不能再试」,而在「模型必须意识到自己已经在重复」。
这是一种更成熟的代理控制思路:不剥夺能力,先强化自知。
🎓 系统提示:代理行为的核心驱动力
Dexter 的代理行为,很大程度上来自系统提示。系统提示通常由这些部分组成:
- 基础身份和行为约束
- 工具描述(描述即行为)
- 技能元数据
- 记忆说明
- 心跳说明
- 渠道特定格式约束
SOUL.md身份文档
关键洞察:工具的“说明书”直接影响模型行为。工具描述写得清楚,规划就更稳定;写得模糊,模型就更容易误用能力。
🚀 快速上手
环境准备
# 1. 安装依赖(包含 playwright chromium)
bun install
# 2. 配置环境变量
cp env.example .env
# 至少填写:
# OPENAI_API_KEY=your-key
# FINANCIAL_DATASETS_API_KEY=your-key(强烈建议)
# EXASEARCH_API_KEY=your-key(强烈建议)
# 3. 启动 CLI
bun run start建议的最小配置组合
| 场景 | 必需 | 强烈建议 |
|---|---|---|
| 最快启动 | OPENAI_API_KEY | - |
| 完整研究体验 | OPENAI_API_KEY | FINANCIAL_DATASETS_API_KEY、EXASEARCH_API_KEY |
| 本地模型探索 | OLLAMA_BASE_URL | - |
首次验证问题
Compare Apple and Microsoft on revenue growth, operating margin, and free cash flow trend over the last 5 years.为什么不用“你是谁”? 因为这类问题无法验证工具链是否真的工作正常。
💡 研究工作流最佳实践
推荐的提问模板
对象 + 时间范围 + 比较维度 + 目标判断 + 期望输出格式把「描述」升级成「判断」
不要只问:
What is Tesla's latest revenue?而要问:
What does Tesla's latest revenue, gross margin, and operating income suggest about demand quality and pricing power?🔧 扩展开发:新增工具与技能
新增工具的完整路径
- 实现工具逻辑(使用
zodschema 定义参数) - 写 rich description(描述即行为!)
- 注册到工具表(
src/tools/registry.ts) - 确认启用条件
- 验证 Agent 行为
工具设计的 6 条硬建议
- 名字要表达意图,而不是实现细节
- 一个工具只承担一类稳定职责(「万能工具」最难正确使用)
- 输出尽量结构化(返回 JSON 而不是自由文本)
- 写清楚不该使用的场景
- 对成本高的工具要明确边界
- 先为代理设计,再为人类设计
技能设计的 5 条硬建议
- 技能要针对可复用工作流(一次性技巧不适合)
- frontmatter 的描述要精准(过宽导致误命中,过窄永远不被调用)
- 强调步骤和边界(不是散文,是执行指令)
- 使用相对链接引用配套材料
- 控制技能长度(越长不等于越强)
📁 关键配置参考
环境变量速查
| 变量 | 作用 | 推荐 |
|---|---|---|
OPENAI_API_KEY | OpenAI 模型 | 常用 |
FINANCIAL_DATASETS_API_KEY | 金融数据 | 强烈建议 |
EXASEARCH_API_KEY | 网页搜索 | 强烈建议 |
PERPLEXITY_API_KEY | 搜索回退 | 按需 |
TAVILY_API_KEY | 搜索回退 | 按需 |
X_BEARER_TOKEN | X 搜索 | 按需 |
OLLAMA_BASE_URL | 本地模型 | 按需 |
关键本地文件
| 路径 | 作用 |
|---|---|
.env | 环境变量 |
.dexter/settings.json | 模型和记忆偏好 |
.dexter/gateway.json | 网关、心跳配置 |
.dexter/HEARTBEAT.md | 心跳监控清单 |
.dexter/memory/ | 持久记忆文件 |
.dexter/credentials/ | WhatsApp 凭据 |
🔍 故障排查
常见症状与根因
| 症状 | 先检查 |
|---|---|
| CLI 无法启动 | bun install 是否执行、是否在仓库根目录 |
| API Key 问题 | .env 是否存在、Key 是否仍是占位符 |
| 金融问题答得空 | 金融工具是否被触发、FINANCIAL_DATASETS_API_KEY |
| 网页问题差 | 搜索 Key 是否配置、browser 依赖是否安装 |
| WhatsApp 不回消息 | bun run gateway 是否运行、号码是否在 allowFrom |
| 自动化无提醒 | 网关是否可用、消息是否写得过于含糊 |
| 记忆「记不住」 | 是否使用了 memory_update、嵌入提供商是否可用 |
最小恢复策略
1. 检查 .env
2. 重新运行 bun install
3. 重新启动 CLI 或网关
4. 重试一个最小可验证问题
5. 必要时重建网关登录状态📌 总结
一句话定义
Dexter 是一个以研究为导向的 AI 代理平台,通过多模型路由、工具协同、技能复用、持久记忆、WhatsApp 网关和自动化监控的完整架构,让 AI 不是「会说」,而是「能查、能做、能监控、能进化」。
核心价值矩阵
| 能力 | 给用户带来的价值 |
|---|---|
| 金融工具链 | 专业级金融研究不需要手动查数据 |
| 多模型路由 | 根据任务选择最合适的模型 |
| 技能系统 | 复杂方法论可沉淀、可复用 |
| 持久记忆 | 长期协作不需要重复说明偏好 |
| WhatsApp 网关 | 随时随地发起研究 |
| 自动化监控 | 被动等待 → 主动通知 |
与传统 CLI 的本质区别
| 维度 | 传统 CLI | Dexter |
|---|---|---|
| 回答质量 | 依赖模型自身知识 | 依赖真实工具数据 |
| 执行模式 | 单轮响应 | 多轮迭代、工具协同 |
| 记忆能力 | 无 | 跨会话持久记忆 |
| 自动化 | 无 | Heartbeat + Cron |
| 扩展性 | 固定能力 | 技能系统可扩展 |
适合谁?
| 用户类型 | Dexter 能帮你做什么 |
|---|---|
| 金融分析师 | 自动化财报研究、行业对比 |
| 投资者 | 持续监控标的、系统化决策 |
| 研究者 | 快速抓取、整合多源信息 |
| 开发者 | 学习 Agent 系统架构、扩展开发 |
| 技术管理者 | 理解 AI Agent 的能力边界和设计取舍 |
🦞 钳岳星君整理|2026 年 3 月 26 日
📚 延伸阅读
- Dexter GitHub:A1pha3/dexter
- 中文文档中心:docs/cn
- 系统架构详解:system-architecture.md
- Agent 循环机制:agent-loop-and-context.md