第四次作业

这个作业属于哪个课程 Class56-Grade2024-CS
这个作业要求在哪里 作业要求
这个作业的目标 个人 Agent 助手说明文档的梳理与格式规范化:整理项目需求、业务流、实现说明与使用示例,形成结构清晰的 Markdown 文档
学号 3124004075 郑剀元,3124004053 陈梓铤

个人 Agent 助手说明文档

项目名称:个人 Agent 助手
项目类型:本地 CLI Agent + Web UI
仓库位置:https://github.com/Zztt417/----3/tree/main/第四次作业
技术栈:Python、FastAPI、Vue 3、Vite、Chroma、sentence-transformers、MCP
使用方式:命令行 / 浏览器


一、需求描述

1.1 项目定位

本项目是一个运行在本机的个人 Agent 助手,核心目标是:

接收用户输入 → LLM 判断是否需要调用工具 → 执行工具 → 把结果返回给 LLM → 继续推理,直到给出最终答案。

项目参考 nanobot 的极简架构,重点拆解并实现以下能力:

  • OpenAI 兼容 LLM 接入
  • ReAct 工具调用循环
  • 本地工具注册与执行
  • 短期记忆与长期记忆
  • 多会话隔离
  • FastAPI 接口
  • Vue 3 Web 界面
  • MCP 外部工具扩展

1.2 功能需求

编号 需求 说明
F1 CLI 交互 命令行 REPL,支持连续对话和退出
F2 LLM 接入 支持 OpenAI 兼容接口,模型从配置读取
F3 ReAct 循环 支持一次返回多个工具调用,结果回填后继续推理
F4 本地工具 文件读写、Shell 命令、网页搜索、网页抓取、PDF 解析
F5 短期记忆 每会话独立持久化;滑动窗口 + 溢出摘要压缩
F6 长期记忆 本地 Chroma 向量库 + bge 中文向量模型
F7 会话管理 新建、切换、列出、删除、查看历史
F8 Web UI Vue 3 聊天界面、会话列表、运行状态面板
F9 FastAPI 暴露聊天、会话、历史和状态接口
F10 MCP 扩展 可选接入邮件 MCP 工具
F11 安全配置 真实密钥不进入仓库,API 默认仅监听本机
F12 安全上传 提供 GitHub 上传前安全检查脚本

1.4 使用约束

本项目默认是个人本地工具:

  • run_shell 可以执行本机命令
  • read_file / write_file 可以访问本机文件
  • FastAPI 默认只监听 127.0.0.1
  • 不建议直接暴露到公网
  • 真实密钥必须放在仓库外

二、业务流描述

2.1 整体架构

┌──────────────────────┐
│      Vue 3 Web UI     │
│  会话列表 / 聊天 / 状态 │
└──────────┬───────────┘
           │ HTTP /api
           ▼
┌──────────────────────┐
│       FastAPI         │
│ 聊天 / 会话 / 历史接口 │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│        Agent          │
│  ReAct + Session      │
└──────┬───────┬───────┘
       │       │
       ▼       ▼
┌──────────┐ ┌──────────────┐
│ LLMClient│ │ ToolRegistry │
└──────────┘ └──────┬───────┘
                    │
      ┌─────────────┼─────────────┐
      ▼             ▼             ▼
  文件/Shell     网页/PDF        MCP 工具
      │             │             │
      └─────────────┴─────────────┘
                    │
                    ▼
           短期记忆 / 长期记忆

2.2 启动流程

CLI 启动

python main.py
    │
    ▼
load_config()
    │
    ├─ 读取外部 .env / 项目 .env
    ├─ 初始化 LLMClient
    ├─ 初始化短期记忆
    ├─ 初始化 Chroma 长期记忆
    ├─ 加载会话索引
    ├─ 注册工具
    ├─ 可选连接 MCP
    └─ 进入 REPL 循环

Web 启动

python api_server.py
    │
    ▼
FastAPI lifespan
    │
    ├─ 组装 Agent 运行时
    ├─ 加载模型 / 记忆 / 工具
    ├─ 可选连接 MCP
    ├─ 托管 ui/dist
    └─ 提供 /api 接口

2.3 单轮对话主流程

用户输入
   │
   ├─ 以 "/" 开头 → CLI 命令处理
   │
   └─ 普通文本
        │
        ▼
  Agent.run(user_input, session_id)
        │
        ├─ 设置当前会话
        ├─ 短期记忆检查与压缩
        ├─ 检索当前会话长期记忆
        ├─ 写入用户消息
        ├─ 组装 messages + tools
        │
        ▼
  for step in range(max_steps)
        │
        ├─ 调用 LLM
        ├─ 写入 assistant 消息
        ├─ 无 tool_calls → 返回最终答案
        │
        └─ 有 tool_calls
             ├─ 执行每个工具
             ├─ 写入 tool 消息
             └─ 继续下一轮

2.4 ReAct 循环

Agent 每轮最多执行 MAX_STEPS 次“模型调用 + 工具执行”循环。

关键约束:

  • assistant 的 tool_calls[].id 必须与 tool 消息的 tool_call_id 对应
  • 工具结果必须回填给模型
  • 工具异常不能中断整个循环,而是转成错误文本回填
  • 工具调用过程默认不展示,只展示最终结论
  • 超过最大步数时返回提示,避免无限循环

2.5 短期记忆流程

短期记忆采用:

滑动窗口 + 超出部分摘要压缩

流程:

每轮追加 user / assistant / tool 消息
        │
        ▼
消息条数 > MEMORY_MAX_MESSAGES
        │
        ├─ 否:继续
        │
        └─ 是:
             ├─ 找到安全切点
             ├─ 较早消息交给 LLM 摘要
             ├─ 摘要写入 system 上下文
             ├─ 保留最近一段原始消息
             └─ 重写 JSONL

切点会尽量对齐到 user 消息,避免切断工具调用与工具结果。

2.6 长期记忆流程

写入:

LLM 调用 memory_save
        │
        ▼
读取当前 session_id
        │
        ▼
bge-small-zh-v1.5 生成向量
        │
        ▼
写入 Chroma
  document: 记忆正文
  metadata:
    session_id: 会话 ID
    timestamp: 时间
    type: fact / preference / conclusion
    tags: 标签

读取:

用户输入
   │
   ▼
生成查询向量
   │
   ▼
Chroma.query(
  where={"session_id": 当前会话},
  n_results=top_k
)
   │
   ▼
把命中记忆注入本轮 system 上下文

默认会话隔离;跨会话检索必须由用户明确要求。

2.7 会话管理流程

动作 流程
新建 生成会话 ID → 写入 index.json → 切换
切换 更新最近使用时间 → 加载对应 JSONL
删除 删除长期记忆 → 删除 JSONL → 删除索引
历史 读取 JSONL,过滤工具消息,展示用户/助手消息
自动命名 首次对话后用用户输入生成标题

2.8 Web 请求流程

Vue 页面
   │
   ├─ GET /api/sessions
   ├─ GET /api/sessions/{id}/history
   ├─ POST /api/chat
   └─ GET /api/status
        │
        ▼
FastAPI
        │
        ▼
AgentRuntime(进程内单例)
        │
        ▼
Agent + Memory + Tools + LLM

API 使用锁保证同一时间只有一个聊天请求修改 Agent 状态,避免会话历史和记忆索引并发写入冲突。


三、实现说明

3.1 目录结构

个人agent助手/
├── main.py                    CLI 启动入口
├── api_server.py              FastAPI 启动入口
├── mybot/
│   ├── agent.py               ReAct 循环
│   ├── api.py                 FastAPI 接口
│   ├── config.py              配置加载
│   ├── llm.py                 LLM 客户端
│   ├── memory.py              短期记忆
│   ├── long_memory.py         Chroma 长期记忆
│   ├── sessions.py            会话索引
│   ├── session_scope.py       ContextVar 会话作用域
│   ├── mcp_client.py          MCP 同步桥接
│   └── tools/
│       ├── base.py            Tool / ToolResult
│       ├── registry.py        工具注册表
│       ├── builtin.py         文件与 Shell
│       ├── web.py             搜索与网页抓取
│       ├── pdf_tools.py       PDF 解析
│       └── memory_tools.py    记忆工具
├── ui/                        Vue 3 + Vite 前端
├── models/                    本地 bge 向量模型
├── samples/                   合成 PDF 测试样本
├── scripts/                   安全检查脚本
├── .env.example               配置模板
├── README.md                  部署使用说明
├── SECURITY.md                安全说明
└── requirements.txt

3.2 核心模块职责

模块 职责
config.py 加载 LLM、记忆、MCP、API 配置
llm.py 封装 OpenAI 兼容 Chat Completions 接口
agent.py 组装消息、执行 ReAct 循环、调用工具
memory.py JSONL 短期记忆、摘要压缩、会话 LRU
long_memory.py Chroma 向量库、bge 嵌入、语义检索
sessions.py 会话索引、标题、时间、增删改查
session_scope.py 用 ContextVar 传递当前会话 ID
tools/base.py 工具抽象与统一返回结构
tools/registry.py 工具注册、schema 导出、异常兜底
mcp_client.py 后台线程运行异步 MCP,对外提供同步接口
api.py FastAPI 路由、运行时装配、静态 UI 托管
ui/ 会话侧栏、聊天区、状态面板、Markdown 渲染

3.3 消息结构

系统使用 OpenAI Chat Completions 消息格式:

role 说明
system 基础提示词 + 历史摘要 + 长期记忆
user 用户输入
assistant 模型回复,可能带 tool_calls
tool 工具执行结果,带 tool_call_id

工具调用必须保持:

assistant(tool_calls)
    → tool(tool_call_id)

的顺序,否则接口可能报错。

3.4 工具接口

所有工具实现统一接口:

class Tool:
    name: str
    description: str
    parameters: dict
    def execute(self, **kwargs) -> ToolResult: ...

工具执行失败时返回 ToolResult.error(...),由 Agent 回填给模型,而不是直接抛出异常。

3.5 关键技术决策

决策 原因
工具使用同步接口 实现简单,便于调试
MCP 使用后台线程桥接 MCP SDK 是异步的,但上层工具是同步的
会话 ID 使用 ContextVar 工具实例全局唯一,避免模型自行填写会话 ID
摘要压缩只在回合开始 避免切断 tool_calls 与 tool 结果
长期记忆按 session_id 过滤 实现会话间物理隔离
PDF 缩进按 x 坐标聚类 PDF 没有显式缩进结构
FastAPI 使用 RLock 避免多请求并发修改 Agent 状态
真实配置放在仓库外 防止密钥进入 Git
ui/dist 随仓库提交 不安装前端依赖也能直接启动 Web UI

3.6 配置读取

配置读取优先级:

MYBOT_ENV_FILE
  > 项目根目录 .env
  > 用户目录 ~/.mybot/.env

推荐使用仓库外的用户配置:

Windows: C:\Users\<用户名>\.mybot\.env
macOS/Linux: ~/.mybot/.env

3.7 数据存储

数据 位置
短期记忆 MEMORY_DATA_DIR/sessions/*.jsonl
会话索引 MEMORY_DATA_DIR/sessions/index.json
长期向量库 MEMORY_DATA_DIR/chroma
嵌入模型 models/bge-small-zh-v1.5
运行时日志 .mybot/mcp.log(启用 MCP 时)

默认 MEMORY_DATA_DIR 为项目内 data/,可用环境变量覆盖。

3.8 安全实现

  • .env、.mybot/、data/、数据库文件和个人 PDF 已加入 .gitignore
  • .env.example 只包含占位符
  • 提供 scripts/check_github_safety.py 上传前扫描
  • FastAPI 默认监听 127.0.0.1:8000
  • 邮件 MCP 默认关闭
  • 邮件授权码保存在 MCP 自己的本地配置库,不进入项目
  • run_shell 等工具没有沙箱,需限制在本机可信环境使用

四、使用示例(功能演示)

4.1 安装

cd "<项目根目录>"
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt

macOS / Linux:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

4.2 配置

复制配置模板到用户目录:

New-Item -ItemType Directory -Force "$HOME\.mybot" | Out-Null
Copy-Item .env.example "$HOME\.mybot\.env"
notepad "$HOME\.mybot\.env"

填写:

OPENAI_API_KEY=sk-your-key-here
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4o-mini

也可以使用 DeepSeek:

OPENAI_BASE_URL=https://api.deepseek.com/v1
OPENAI_MODEL=deepseek-flash

4.3 启动 CLI

python main.py

示例:

你 > 帮我读取 README.md,概括这个项目
助手 > 这个项目是一个本地个人 Agent……

会话命令:

/sessions
/new 项目笔记
/switch 1
/history 5
/delete 2 -y
/help
exit

4.4 启动 Web UI

python api_server.py

打开:

http://127.0.0.1:8000

接口文档:

http://127.0.0.1:8000/docs

前端开发模式:

cd ui
npm install
npm run dev

打开:

http://127.0.0.1:5173

4.5 文件读取示例

输入:

读取 requirements.txt,告诉我项目依赖了哪些库

Agent 会调用:

read_file(path="requirements.txt")

最终回答会列出依赖,例如:

openai、python-dotenv、chromadb、sentence-transformers、
pdfplumber、mcp、fastapi、uvicorn

4.6 文件写入示例

输入:

在当前目录创建 notes.txt,内容为“今天完成了 Agent Web UI”

Agent 会调用:

write_file(path="notes.txt", content="今天完成了 Agent Web UI")

4.7 Shell 示例

输入:

运行 python --version,告诉我当前 Python 版本

Agent 会调用:

run_shell(command="python --version")

4.8 网页搜索示例

输入:

搜索 Vue 3 + FastAPI 本地 Agent 的实践文章

Agent 会调用:

web_search(query="Vue 3 FastAPI 本地 Agent")

需要正文时可以继续抓取某个链接:

web_fetch(url="https://example.com/article")

4.9 PDF 解析示例

项目自带合成测试文件:

samples/_synthetic_nested.pdf

输入:

解析 samples/_synthetic_nested.pdf 的第 1 页

Agent 会调用:

pdf_parse(path="samples/_synthetic_nested.pdf", pages="1")

输出会包含正文和 Markdown 表格,并用全角空格保留缩进层级。

扫描件/图片型 PDF 没有文本层,当前工具不支持 OCR。

4.10 短期记忆示例

在同一会话中:

你 > 记住:我的项目使用 FastAPI + Vue 3
助手 > 已记住。

后续:

你 > 我的项目使用什么技术栈?
助手 > 你的项目使用 FastAPI + Vue 3。

4.11 长期记忆示例

你 > 记住:我喜欢喝美式咖啡
助手 > 已记入当前会话的长期记忆。

重启程序或切换到同一会话后:

你 > 我喜欢喝什么?
助手 > 你喜欢喝美式咖啡。

不同会话默认不会共享长期记忆。

4.12 跨会话检索示例

用户明确要求:

查一下我在其他对话里提到过什么饮品

Agent 可能调用:

memory_search_other_sessions(query="饮品")

返回结果会标注来源会话。

4.13 会话管理示例

你 > /sessions
会话列表(最近使用在前):
  1. 项目笔记
  2. 默认会话

你 > /new 课程表分析
已新建并切换到会话:课程表分析

你 > /history 5
—— 最近 5 条对话 ——

4.14 邮件 MCP 示例(可选)

默认关闭:

MCP_EMAIL_ENABLED=false

需要时先配置:

python -m pip install uv
uvx mcp-email-server@latest ui

在本地 MCP UI 中填写账号、SMTP/IMAP 地址和授权码,然后把本地配置改为:

MCP_EMAIL_ENABLED=true

重启 API 或 CLI 后,可以输入:

给白名单里的邮箱发一封测试邮件,主题是“MCP 测试”

授权码不要写入 .env.example、README、代码或聊天记录。

4.15 API 调用示例

PowerShell:

$body = @{
  session_id = "default"
  message = "读取 requirements.txt,概括项目依赖"
} | ConvertTo-Json

Invoke-RestMethod `
  -Uri "http://127.0.0.1:8000/api/chat" `
  -Method Post `
  -ContentType "application/json" `
  -Body $body

示例返回:

{
  "answer": "项目依赖包括……",
  "session": {
    "id": "default",
    "title": "项目依赖说明",
    "memory_count": 0
  },
  "session_id": "default"
}

4.16 常见问题

现象 处理方法
提示未找到 OPENAI_API_KEY 检查 ~/.mybot/.env 或 MYBOT_ENV_FILE
长期记忆已禁用 检查 models/bge-small-zh-v1.5,缺失时运行 python setup_memory.py
缺少 fastapi 执行 pip install -r requirements.txt
MCP 工具为 0 检查 MCP 配置,或设置 MCP_EMAIL_ENABLED=false
8000 端口被占用 修改 API_PORT
前端页面打不开 检查 ui/dist/index.html,必要时运行 npm run build
PDF 无内容 可能是扫描件,需要 OCR
上传 GitHub 前不确定是否安全 执行 python scripts\check_github_safety.py

总结

本项目实现了一个可本地运行的 Agent 助手:

  • CLI 与 Web UI 共用同一套 Agent 能力
  • 通过 ReAct 循环完成真实工具调用
  • 使用短期滑动窗口和长期向量记忆维持上下文
  • 通过 FastAPI 暴露稳定接口
  • 通过 Vue 3 提供可视化操作界面
  • 通过 MCP 支持外部工具扩展
  • 默认将密钥和运行数据隔离在仓库外

适合用于个人本地自动化、学习 Agent 架构、演示工具调用和二次开发。

posted @ 2026-10-21 16:53  zkyy  阅读(16)  评论(0)    收藏  举报