好的!我们用 全 JavaScript/TypeScript 技术栈 来搭建这个多 Agent 系统的 最小可行性原型(MVP)。我们会从最核心的功能开始,逐步迭代,让你快速看到效果。
一、MVP 核心范围与技术选型
MVP 核心目标(先做这3件事)
- 数据采集:获取 BTC/USDT 现货行情数据(K线、成交量)
- 双 Agent 协同:实现「技术面分析 Agent」+「决策融合 Agent」的基础协同
- 极简交互:一个简单的 Web 界面,输入标的,输出分析报告
全 JS 技术栈
| 模块 | 技术选型 | 说明 |
|---|---|---|
| 运行环境 | Node.js 20+ | 后端/Agent 运行环境 |
| Agent 编排 | LangChain.js (LangGraph) | 核心:JS 版的多 Agent 状态管理与流程控制 |
| 大模型 | OpenAI GPT-4o (API) / Ollama (本地 Llama 3) | 闭源/开源二选一,都有完善的 JS SDK |
| 数据采集 | CCXT (JS版) | 对接全球交易所的统一 API |
| 链上数据 | Viem / Ethers.js v6 | 轻量级以太坊/链上数据交互 |
| 数据库 | SQLite (better-sqlite3) | 轻量级,无需额外安装服务,Node.js 原生支持 |
| 缓存 | ioredis (可选) | 缓存行情数据,减少 API 调用 |
| 后端框架 | Express.js | Node.js 生态最成熟的轻量级 Web 框架 |
| 前端框架 | VitePress(在 docs/ 目录,通过 API 调用后端) | |
| 可视化 | ECharts / TradingView Lightweight Charts | 行情图表展示 |
二、第一步:环境搭建与项目初始化
1. 基础环境准备
确保你已安装:
- Node.js 20+ (推荐使用 nvm 管理)
- 代码编辑器 (VS Code)
- Git (可选,用于版本管理)
2. 创建项目目录
bash
# 创建并进入项目文件夹
mkdir crypto-agent-express-mvp
cd crypto-agent-express-mvp
# 初始化 Node.js 项目
npm init -y
# 安装 TypeScript (可选但推荐,保持类型安全)
npm install -D typescript @types/node tsx
npx tsc --init3. 安装核心依赖
bash
# 后端框架与中间件
npm install express cors dotenv
# Agent 与 AI 相关
npm install langchain @langchain/langgraph @langchain/openai
# 数据与工具
npm install ccxt better-sqlite3 viem4. 配置环境变量
在项目根目录创建 .env.local 文件:
txt
# 大模型 API (二选一,推荐先用 OpenAI 快速验证)
OPENAI_API_KEY=你的_OpenAI_API_Key
# 如果用本地 Ollama (无需 API Key)
# OLLAMA_BASE_URL=http://localhost:11434
# OLLAMA_MODEL=llama3:70b
# 数据库路径 (默认即可)
DATABASE_URL=./crypto_data.db三、第二步:数据层开发(行情数据采集)
先实现最基础的行情数据采集,用 CCXT 获取 Binance 的 BTC/USDT 数据。
1. 创建数据采集模块
在 app/lib/ 目录下创建 marketData.ts:
typescript
// app/lib/marketData.ts
import ccxt from 'ccxt';
// 初始化 Binance 交易所 (仅读取行情,无需 API Key)
const exchange = new ccxt.binance({
enableRateLimit: true, // 开启限流,避免被封
});
// 获取 K线数据
export async function fetchKlineData(
symbol: string = 'BTC/USDT',
timeframe: string = '1h',
limit: number = 100
) {
try {
const ohlcv = await exchange.fetchOHLCV(symbol, timeframe, undefined, limit);
// 格式化数据,方便后续处理
return ohlcv.map(kline => ({
timestamp: kline[0],
open: kline[1],
high: kline[2],
low: kline[3],
close: kline[4],
volume: kline[5],
}));
} catch (error) {
console.error('获取行情数据失败:', error);
throw error;
}
}2. 简单测试数据采集
在 app/api/test-data/route.ts 创建一个测试接口:
typescript
// app/api/test-data/route.ts
import { NextResponse } from 'next/server';
import { fetchKlineData } from '@/lib/marketData';
export async function GET() {
const data = await fetchKlineData('BTC/USDT', '1h', 50);
return NextResponse.json({ data });
}启动项目 npm run dev,访问 http://localhost:3000/api/test-data,如果能看到 K线数据,说明数据层通了!
四、第三步:核心 Agent 开发(用 LangChain.js)
我们先实现两个核心 Agent:技术面分析 Agent 和 决策融合 Agent。
1. 初始化 LangChain 与大模型
在 app/lib/agents/ 下创建 llm.ts:
typescript
// app/lib/agents/llm.ts
import { ChatOpenAI } from '@langchain/openai';
// 初始化 GPT-4o (如果用 Ollama,换成 ChatOllama)
export const llm = new ChatOpenAI({
model: 'gpt-4o',
temperature: 0.1, // 温度低一点,分析更严谨
apiKey: process.env.OPENAI_API_KEY,
});2. 技术面分析 Agent
这个 Agent 的职责是:接收 K线数据,用大模型分析技术面,输出多空观点。 创建 app/lib/agents/technicalAnalysisAgent.ts:
typescript
// app/lib/agents/technicalAnalysisAgent.ts
import { llm } from './llm';
import { z } from 'zod';
import { StructuredOutputParser } from 'langchain/output_parsers';
// 定义输出格式(用 Zod 结构化,避免大模型瞎输出)
const TechnicalAnalysisOutput = z.object({
trend: z.enum(['bullish', 'bearish', 'neutral']).describe('趋势判断:看涨/看跌/震荡'),
keySupport: z.number().describe('关键支撑位'),
keyResistance: z.number().describe('关键阻力位'),
reasoning: z.string().describe('分析逻辑,100字以内'),
});
const parser = StructuredOutputParser.fromZodSchema(TechnicalAnalysisOutput);
// 技术面分析 Agent 主函数
export async function technicalAnalysisAgent(klineData: any[]) {
// 1. 准备 Prompt
const formatInstructions = parser.getFormatInstructions();
const prompt = `
你是一个资深加密货币技术面分析师。请分析以下 BTC/USDT 1小时 K线数据,给出技术面判断。
K线数据(最近20根):
${JSON.stringify(klineData.slice(-20), null, 2)}
要求:
1. 判断当前趋势(看涨/看跌/震荡)
2. 给出关键支撑位和阻力位
3. 简要说明分析逻辑
${formatInstructions}
`;
// 2. 调用大模型
const response = await llm.invoke(prompt);
// 3. 解析结构化输出
try {
return parser.parse(response.content as string);
} catch (e) {
console.error('解析技术面分析失败:', e);
return {
trend: 'neutral',
keySupport: klineData[klineData.length - 1].low * 0.98,
keyResistance: klineData[klineData.length - 1].high * 1.02,
reasoning: '数据解析失败,给出中性判断',
};
}
}3. 决策融合 Agent
这个 Agent 负责汇总所有分析(目前只有技术面),生成最终报告。 创建 app/lib/agents/decisionAgent.ts:
typescript
// app/lib/agents/decisionAgent.ts
import { llm } from './llm';
export async function decisionAgent(technicalAnalysis: any) {
const prompt = `
你是一个加密货币交易决策助手。请根据以下技术面分析,生成一份简洁的行情分析报告。
技术面分析结果:
${JSON.stringify(technicalAnalysis, null, 2)}
报告要求:
1. 标题:BTC/USDT 1小时行情分析
2. 核心观点:一句话总结
3. 技术面解读:翻译成人话,不要太技术
4. 操作建议:轻仓尝试方向,止损止盈参考支撑阻力
5. 风险提示:必写,提示市场高风险
请用 Markdown 格式输出,控制在300字以内。
`;
const response = await llm.invoke(prompt);
return response.content as string;
}五、第四步:多 Agent 编排(用 LangGraph)
现在我们用 LangGraph 把这两个 Agent 串起来,形成一个简单的工作流。
创建 app/lib/workflow.ts:
typescript
// app/lib/workflow.ts
import { StateGraph, END } from '@langchain/langgraph';
import { technicalAnalysisAgent } from './agents/technicalAnalysisAgent';
import { decisionAgent } from './agents/decisionAgent';
import { fetchKlineData } from './marketData';
// 1. 定义状态(State):工作流中流转的数据
interface AgentState {
klineData?: any[];
technicalAnalysis?: any;
finalReport?: string;
}
// 2. 定义工作流节点
const workflow = new StateGraph<AgentState>({
channels: {
klineData: null,
technicalAnalysis: null,
finalReport: null,
},
})
// 节点1:获取行情数据
.addNode('fetchData', async (state: AgentState) => {
console.log('正在获取行情数据...');
const klineData = await fetchKlineData('BTC/USDT', '1h', 100);
return { klineData };
})
// 节点2:技术面分析
.addNode('technicalAnalysis', async (state: AgentState) => {
console.log('正在进行技术面分析...');
const analysis = await technicalAnalysisAgent(state.klineData!);
return { technicalAnalysis: analysis };
})
// 节点3:生成最终报告
.addNode('generateReport', async (state: AgentState) => {
console.log('正在生成分析报告...');
const report = await decisionAgent(state.technicalAnalysis!);
return { finalReport: report };
});
// 3. 定义边(流程顺序)
workflow
.setEntryPoint('fetchData') // 入口
.addEdge('fetchData', 'technicalAnalysis')
.addEdge('technicalAnalysis', 'generateReport')
.addEdge('generateReport', END); // 结束
// 4. 编译工作流
export const app = workflow.compile();六、第四步:Express 后端服务搭建
1. API 路由 (src/routes/analyze.ts)
创建分析接口,触发工作流:
typescript
// src/routes/analyze.ts
import express from 'express';
import { app as workflow } from '../lib/workflow';
const router = express.Router();
// POST /api/analyze
router.post('/', async (req, res) => {
try {
console.log('收到分析请求,启动工作流...');
// 触发 LangGraph 工作流
const result = await workflow.invoke({});
res.json({
success: true,
data: {
report: result.finalReport,
technicalAnalysis: result.technicalAnalysis,
}
});
} catch (error) {
console.error('工作流执行失败:', error);
res.status(500).json({
success: false,
message: '分析失败,请稍后重试',
});
}
});
export default router;2. 后端入口文件 (src/index.ts)
启动 Express 服务,托管前端静态文件:
typescript
// src/index.ts
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import path from 'path';
import analyzeRouter from './routes/analyze';
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3001;
// 中间件
app.use(cors()); // 允许跨域
app.use(express.json());
// 托管前端静态文件 (public 目录)
app.use(express.static(path.join(__dirname, 'public')));
// API 路由
app.use('/api/analyze', analyzeRouter);
// 启动服务
app.listen(PORT, () => {
console.log(`
🚀 服务已启动!
📡 后端 API: http://localhost:${PORT}/api/analyze
🌐 前端页面: http://localhost:${PORT}
`);
});关键注意事项
- 先跑通 MVP,再谈优化:不要一开始就想做全,先让两个 Agent 跑起来,有正向反馈再迭代
- 善用开源库:CCXT、LangChain.js 帮你省了几年的开发量,不要重复造轮子
- 数据安全第一:永远不要把 API Key 上传到 GitHub,本地测试用环境变量
- 敬畏市场:这只是一个技术原型,不要直接用于实盘交易!实盘前必须经过严格的回测和模拟盘验证
需要我帮你深入实现其中某个具体模块(比如链上分析 Agent 或 LangGraph 并行工作流)吗?
