基于 NestJS + Next.js 构建的全栈 TypeScript 应用,利用 LangChain 和 Exa Search 实现智能化信源追溯
FindAgent 是一个多智能体信息源验证助手,能够:
- 分析文章内容,识别关键陈述和事实性声明
- 自动追溯和验证信息的一手来源
- 通过多智能体协同工作,提供可验证的证据和引用
- 帮助用户区分原始来源和二次转载内容
- 异步任务处理,支持长时间运行的分析任务
- 完整的历史记录管理和查询功能
┌─────────────────┐ HTTP/REST ┌──────────────────┐
│ Next.js 前端 │ ◄────────────────► │ NestJS 后端服务 │
│ (React UI) │ │ (智能体编排) │
└─────────────────┘ └──────────────────┘
│
├─► LangChain + GLM-4.6
├─► Exa Search API
└─► SQLite 数据库
架构特点:
- 全栈 TypeScript,类型安全
- 异步任务队列,后台执行 AI 分析
- 实时状态轮询,用户体验友好
- SQLite 持久化存储任务历史
- RESTful API + Swagger 文档
- 框架: Next.js 16 (App Router) + React 19
- 语言: TypeScript 5.7+
- 样式: Tailwind CSS 4
- UI 库: shadcn/ui (Radix UI primitives)
- 图标: lucide-react
- HTTP 客户端: Axios
- Markdown: react-markdown + remark-gfm
- 框架: NestJS 11 + TypeScript
- AI 编排: LangChain (@langchain/core, @langchain/openai)
- LLM: GLM-4.6 (通过 OpenAI 兼容接口)
- 搜索引擎: Exa.ai API (智能网络搜索)
- 数据库: SQLite (better-sqlite3)
- 验证: class-validator + class-transformer
- 文档: Swagger/OpenAPI (@nestjs/swagger)
- 监控: LangSmith (可选)
- Node.js 20+
- npm 或 pnpm
git clone <repository-url>
cd findAgent-master复制配置模板:
cd refactoring-agent-service
cp config/dev.example.yaml config/dev.yaml编辑 config/dev.yaml 配置你的 API 密钥:
Agent:
superior_agent:
model: glm-4.6
api_key: YOUR_AGENT_API_KEY_HERE # 替换为你的 LLM API 密钥
base_url: https://aihubmix.com/v1
model_provider: openai
Exa:
api_key: YOUR_EXA_API_KEY_HERE # 替换为你的 Exa Search API 密钥
api_url: https://api.exa.ai/search
LangSmith:
tracing: true # 可选:开启 LangSmith 追踪
api_key: YOUR_LANGSMITH_API_KEY_HERE
project: findagent安装依赖:
npm installcd ../frontend
npm install创建 .env.local 文件:
NEXT_PUBLIC_API_URL=http://localhost:8000终端 1 - NestJS 后端服务:
cd refactoring-agent-service
npm run start:dev服务将在 http://localhost:8000 启动
终端 2 - Next.js 前端:
cd frontend
npm run dev前端将在 http://localhost:3000 启动
- 前端界面: http://localhost:3000
- 后端 API 文档: http://localhost:8000/docs (Swagger UI)
- 健康检查: http://localhost:8000/api/test
findAgent-master/
├── frontend/ # Next.js 前端
│ ├── app/
│ │ ├── page.tsx # 首页(文章输入)
│ │ ├── chat/[id]/page.tsx # 任务详情页(实时状态)
│ │ └── history/page.tsx # 历史记录管理
│ ├── components/
│ │ ├── features/ # 业务组件
│ │ │ ├── ArticleInput.tsx
│ │ │ ├── ResultDisplay.tsx
│ │ │ └── SourceCard.tsx
│ │ └── ui/ # shadcn/ui 组件
│ ├── lib/
│ │ ├── api/agent.ts # API 客户端
│ │ └── types/agent.ts # TypeScript 类型定义
│ └── hooks/useAgentTask.ts
│
├── refactoring-agent-service/ # NestJS 后端
│ ├── src/
│ │ ├── agents/ # 智能体模块
│ │ │ ├── agent.service.ts # AI 编排逻辑
│ │ │ ├── agent.controller.ts # 任务 API
│ │ │ └── prompts.ts # Prompt 模板
│ │ ├── tools/ # 工具模块
│ │ │ └── tools.service.ts # Exa Search 集成
│ │ ├── database/ # 数据库模块
│ │ │ └── database.service.ts # SQLite 操作
│ │ ├── config/ # 配置模块
│ │ │ └── configuration.ts
│ │ ├── dto/ # 数据传输对象
│ │ ├── common/
│ │ │ └── history.controller.ts # 历史记录 API
│ │ └── main.ts
│ ├── config/
│ │ ├── dev.yaml # 开发环境配置(需自行创建)
│ │ └── dev.example.yaml # 配置模板
│ └── data/
│ └── findagent.db # SQLite 数据库(自动创建)
│
└── README.md
NestJS 后端服务 (http://localhost:8000)
| 端点 | 方法 | 描述 |
|---|---|---|
/api/find-sources |
POST | 提交信源查找任务(异步) |
/api/tasks/:taskId |
GET | 查询任务状态和结果 |
/api/test |
GET | 健康检查 |
| 端点 | 方法 | 描述 |
|---|---|---|
/api/history |
GET | 获取搜索历史(分页、筛选) |
/api/history/:recordId |
GET | 获取单条历史记录 |
/api/history/:recordId |
DELETE | 删除历史记录 |
| 端点 | 方法 | 描述 |
|---|---|---|
/docs |
GET | Swagger UI 交互式文档 |
1. 提交任务(异步):
curl -X POST http://localhost:8000/api/find-sources \
-H "Content-Type: application/json" \
-d '{"content": "据报道,某地发生重大事件..."}'响应:
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"message": "任务已创建,正在处理中..."
}2. 查询任务状态:
curl http://localhost:8000/api/tasks/550e8400-e29b-41d4-a716-446655440000响应(成功时):
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "success",
"content": "据报道,某地发生重大事件...",
"data": {
"statements": [
"识别出的关键陈述 1",
"识别出的关键陈述 2"
],
"sources": [
{
"url": "https://official-site.gov/news/123",
"title": "官方新闻标题",
"why_primary": "这是政府官方发布的一手消息,包含事件的原始信息...",
"evidence_text": "原文摘录:根据调查..."
}
],
"notes": "## 分析说明\n\n本次共找到 3 个一手信源..."
},
"execution_time": 23.45,
"created_at": "2024-01-01T10:00:00.000Z",
"updated_at": "2024-01-01T10:00:23.450Z"
}3. 获取历史记录(分页):
curl "http://localhost:8000/api/history?limit=20&offset=0&status=success"响应:
{
"total": 42,
"items": [
{
"id": 1,
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"content": "据报道...",
"status": "success",
"execution_time": 23.45,
"created_at": "2024-01-01T10:00:00.000Z"
}
],
"limit": 20,
"offset": 0
}- 用户提交后立即返回
task_id - 任务在后台执行,避免超时
- 前端轮询获取实时状态(pending → running → success/error)
- 支持长时间运行的 AI 分析任务
- 自动识别文章中的关键论断、数据、时间、地点
- 将内容拆分为可验证的独立陈述
- AI 驱动的内容分析和提取
- 通过 Exa Search API 查找原始来源
- 优先级排序:官方机构 > 原始研究 > 原始数据集 > 法律文书 > 首发媒体
- 严格验证:拒绝二次来源(维基百科、媒体汇总、社交媒体转发等)
- 提供信源为何是一手资料的详细理由
- 主智能体(Main Agent):任务编排、工具调用、结果汇总
- 最多 10 次迭代循环
- 自主决策何时调用工具(internet_search、fetch_website)
- 结构化输出(JSON)
- SQLite 持久化存储所有任务
- 支持分页、状态筛选
- 记录执行时间、原始响应
- 支持删除功能
1. 用户输入文章
↓
2. 前端 POST /api/find-sources
↓
3. 后端创建异步任务 → 返回 task_id
↓
4. 前端跳转到任务页,开始轮询 GET /api/tasks/:taskId
↓
5. 后端 AI 智能体工作:
- 分析文章,提取关键陈述
- 调用 Exa Search 查找信源
- 验证是否为一手资料
- 生成结构化结果
↓
6. 前端显示实时状态和结果
↓
7. 任务完成,保存到历史记录
后端开发:
cd refactoring-agent-service
npm run start:dev # 开发模式(热重载)
npm run build # 构建生产版本
npm run start:prod # 生产模式
npm run test # 运行测试
npm run lint # ESLint 检查前端开发:
cd frontend
npm run dev # 开发模式
npm run build # 构建生产版本
npm run start # 生产模式
npm run lint # ESLint 检查后端 (refactoring-agent-service/config/dev.yaml):
Agent:
superior_agent:
model: glm-4.6 # LLM 模型名称
api_key: YOUR_KEY # LLM API 密钥
base_url: https://xxx.com/v1 # API 端点
model_provider: openai # 提供商类型
Exa:
api_key: YOUR_EXA_KEY # Exa Search API 密钥
api_url: https://api.exa.ai/search
Proxy: # 可选:HTTP 代理
https_proxy: http://127.0.0.1:7890
http_proxy: http://127.0.0.1:7890
LangSmith: # 可选:LangSmith 追踪
tracing: true
api_key: YOUR_LANGSMITH_KEY
project: findagent
Database:
path: ./data/findagent.db # SQLite 数据库路径前端 (frontend/.env.local):
NEXT_PUBLIC_API_URL=http://localhost:8000search_history 表:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INTEGER | 主键(自增) |
| task_id | TEXT | 任务 UUID(唯一) |
| content | TEXT | 用户输入的文章内容 |
| status | TEXT | pending/running/success/error |
| result_data | TEXT | JSON 格式的结果数据 |
| raw_response | TEXT | 原始 LLM 响应(截断至 10KB) |
| execution_time | REAL | 执行时间(秒) |
| error | TEXT | 错误信息(如有) |
| created_at | TIMESTAMP | 创建时间 |
| updated_at | TIMESTAMP | 更新时间 |
-
检查端口占用:
lsof -i:3000 # 检查前端端口 lsof -i:8000 # 检查后端端口
-
确认依赖已安装:
npm install
-
检查配置文件:
- 确认
refactoring-agent-service/config/dev.yaml存在 - 确认 API 密钥已正确配置
- 确认
-
确认后端服务正在运行:
curl http://localhost:8000/api/test
-
检查
NEXT_PUBLIC_API_URL环境变量 -
查看浏览器控制台的网络请求
-
确认 CORS 配置(NestJS 默认允许所有来源)
-
查看后端日志:
- 检查终端输出的错误信息
- LangChain 调用日志
-
验证 API 密钥:
- LLM API 密钥是否有效
- Exa Search API 密钥是否有效
- 账户是否有足够配额
-
网络连接:
- 确认能访问 LLM API 端点
- 确认能访问 Exa API
- 检查代理配置(如需要)
-
数据库问题:
- 检查
data/目录是否有写权限 - SQLite 数据库是否正常创建
- 检查
- 检查后端是否抛出异常
- 查看
search_history表中的error字段 - 确认 AI 模型 API 是否响应正常
构建镜像:
# 后端
cd refactoring-agent-service
docker build -t findagent-backend .
# 前端
cd frontend
docker build -t findagent-frontend .运行容器:
# 后端
docker run -p 8000:8000 \
-v $(pwd)/config:/app/config \
-v $(pwd)/data:/app/data \
findagent-backend
# 前端
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8000 \
findagent-frontendMIT License
欢迎提交 Issue 和 Pull Request!
在提交代码前,请确保:
- 运行
npm run lint通过代码检查 - 运行
npm run test通过所有测试 - 更新相关文档
如有问题,请提交 GitHub Issue。
Powered by: NestJS + Next.js + LangChain + Exa Search + GLM-4.6