一个面向"个人/家庭预算管理"的 ReAct 智能体作业项目。 项目同时提供 两套并行实现,便于对照学习"底层原理"与"工业级框架"两种做法:
| 版本 | 入口 | 思路 |
|---|---|---|
| 自研 mini 框架 | python3 budget_agent.py |
参考 datawhalechina/hello-agents,手写 LLM/Tool/ReAct 循环,零第三方依赖 |
| LangGraph 工业实现 | python3 -m budget_app_langgraph |
用 LangGraph 的 create_react_agent + LangChain @tool 复用同一套业务函数 |
| Streamlit 对话 UI | streamlit run budget_app_streamlit/app.py |
st.chat_message 聊天气泡, 思考过程折叠, 支持单 Agent / 多 Agent 协作两种模式可切换 |
Streamlit 版默认开启 Reflection + 多 Agent 模式:顾问 → 审计员 → 协调员协作循环,质量明显高于单 Agent。
支持:
- 个人模式 / 家庭模式
- 6 种沟通角色(数据驱动、可一键扩展):
- 严谨理财顾问 / 温和生活助手 / 皇宫总管太监 / 皮卡丘小助手 / 元气JK学妹 / 加勒比海盗船长
- 完整的 ReAct 循环 (Thought → Action → Observation → Final Answer)
- 业务工具:
compute_metrics、detect_risks、compare_history - 跨会话短期记忆 (
budget_memory.json) - 自研版本在 LLM 不可用时自动降级到
MockLLM,无密钥也能演示
agent/
├── budget_agent.py # 自研版命令行入口 (兼容旧用法)
├── README.md
├── requirements.txt
├── .env.example
│
├── hello_agents/ # 自研 mini 框架 (参考 hello-agents 第七章结构)
│ ├── core/ # LLM / Message / Config / Exceptions
│ ├── tools/ # Tool / ToolRegistry
│ └── agents/ # BaseAgent / ReActAgent
│
├── budget_app/ # 业务应用层 (被两个版本共享)
│ ├── main.py # 自研版入口装配
│ ├── cli.py # 输入采集 + 动态角色菜单
│ ├── models.py # BudgetProfile
│ ├── personas.py # 角色注册中心 (PersonaSpec)
│ ├── prompts.py # ReAct 提示词 + persona 注入
│ ├── memory.py # 业务记忆
│ └── tools/ # 业务工具集 (纯 Python 函数)
│
├── budget_app_langgraph/ # LangGraph 并行实现
│ ├── __main__.py # 入口: python3 -m budget_app_langgraph
│ ├── main.py # 装配 + stream 渲染
│ ├── graph.py # 单 Agent: ChatOpenAI + create_react_agent
│ ├── team_graph.py # 多 Agent 协作: advisor + auditor + coordinator + Reflection
│ ├── tools.py # 把 budget_app/tools/* 包装为 LangChain Tool
│ └── state.py # 跨工具共享 BudgetProfile
│
└── budget_app_streamlit/ # Streamlit 对话式 Web UI
├── app.py # st.chat_message 状态机 (sidebar 选角色 + Toggle 多 Agent)
└── chat_runtime.py # 字段校验 + 单 / 多 Agent 两种事件流
关键点:
budget_app/tools/*里的业务函数完全不知道上层用的是自研框架还是 LangGraph, 真正做到"业务逻辑 vs. Agent 框架"解耦。
cp .env.example .env
# 编辑 .env, 填入 LLM_API_KEY / LLM_MODEL_ID / LLM_BASE_URLpython3 budget_agent.py# 首次需要安装依赖 (建议放进虚拟环境)
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
# 国内网络可加 -i https://pypi.tuna.tsinghua.edu.cn/simple
# 运行
.venv/bin/python -m budget_app_langgraph# 同样需要先 pip install -r requirements.txt
.venv/bin/streamlit run budget_app_streamlit/app.py
# 默认 http://localhost:8501 自动打开界面布局:
- 侧边栏:6 个角色按钮 (含 emoji 头像)、实时数据面板、重置对话
- 主区:chat 气泡, 角色与你逐轮对话;ReAct 思考过程在
🔍 智能体思考过程折叠面板里, 默认折叠, 想看的时候展开 - 结果:角色风格的最终建议会作为最后一条 assistant 消息呈现, 顶部下方还能一键 "再算一次" / "换角色"
三个版本的业务逻辑完全共享 (budget_app/tools/* + budget_app/personas.py + budget_app/fields.py),加角色 / 加字段只改一份。
Streamlit Cloud 提供免费的 app 托管:你的 GitHub 仓库 push 后, 它自动拉代码 + 装 requirements.txt + 跑 app.py, 给你一个公开 URL。
.gitignore 已经把以下文件排除, 不会被 push 到 GitHub:
.env ← 你的本地 LLM_API_KEY
.streamlit/secrets.toml ← 本地 secrets (如果有)
budget_memory.json ← 个人财务数据
.venv/ __pycache__/ *.pyc
push 之前再亲自确认一遍:
git status --ignored | grep -E "\.env|secrets\.toml"
# 上面命令应该把它们列在 "Ignored files" 段, 而不是 "untracked / staged".cd /Users/bytedance/agent
git init
git add .
git commit -m "Budget Agent: ReAct + Reflection + Multi-Agent + Streamlit UI"
# 在 GitHub 网页新建一个空仓库 (公开/私有都行), 复制它的 git URL
git remote add origin git@github.com:你的用户名/budget-agent.git
git branch -M main
git push -u origin main
⚠️ Streamlit Community Cloud 的免费计划 要求仓库公开。如果你想私有, 用付费 Snowflake plan, 或者改成把 secrets 通过 Streamlit Cloud 的 UI 配置, 仓库本身不含 secrets 即可放心公开。
-
访问 share.streamlit.io, 用 GitHub 账号登录, 授权它读取你的仓库
-
点 「New app」 → 「Deploy a public app from GitHub」
-
填写:
字段 值 Repository 你的用户名/budget-agentBranch mainMain file path budget_app_streamlit/app.pyPython version 3.11(默认即可, 我们的代码 3.9+ 都能跑) -
展开 「Advanced settings」 → 「Secrets」, 把
.streamlit/secrets.toml.example的内容粘贴进去, 把LLM_API_KEY换成你自己的:LLM_API_KEY = "sk-xxx你的key" LLM_BASE_URL = "https://api.chatanywhere.tech/v1" LLM_MODEL_ID = "gpt-4o-mini"
保存后 Streamlit 会把这些值注入到
st.secrets, 我们的代码app.py:_load_credentials()自动 fallback 到 secrets, 与本地行为一致。 -
点 「Deploy!」
3-5 分钟后你会拿到一个形如 https://budget-agent-你的用户名.streamlit.app 的公开 URL, 任何人打开浏览器都能直接和皮卡丘 / 太监 / 海盗船长聊预算了 🎉
- 第一次跑可能因为冷启动慢一点, 等 30 秒
- 如果首次有依赖装失败, 在 app 设置页 「Manage app」 → 「Logs」 看错误
- 改了代码之后,
git push即自动重新部署, 无需点任何按钮 - Streamlit Cloud 免费版有 CPU/RAM 限额, 我们这个 app 业务逻辑很轻 (LLM 全在远程), 长期不用 sleep 后下次访问会自动唤醒
| 现象 | 解决 |
|---|---|
部署日志显示 ModuleNotFoundError: No module named 'budget_app' |
检查 Main file path 是否填的 budget_app_streamlit/app.py, app.py 顶部的 sys.path 修复会自动生效 |
启动后报 RuntimeError: 未检测到 LLM_API_KEY |
Secrets 没配或 key 名拼错, 注意三个 key 必须是 LLM_API_KEY / LLM_BASE_URL / LLM_MODEL_ID |
| 跑到 LLM 调用时超时 | base_url 选的服务从美国 Streamlit 服务器访问不通; 换 OpenAI 官方或 OpenRouter 等 |
| 想调试 secrets 是否注入 | 临时加一行 st.write({k: '***' for k in st.secrets}) 在 sidebar |
整套交互流程都被角色"接管",告别冰冷的表单:
1. 选择角色 (中性菜单)
↓
2. 角色用自己的口吻打招呼 ← spec.greeting
↓
3. 角色一项一项问财务数据 ← spec.ask_template
↓
4. 角色提示"我去算一下" ← spec.thinking_hint
↓
5. 展示完整 ReAct 思考过程
↓
6. 角色提示"算完了你看看" ← spec.done_hint
↓
7. 角色风格的最终建议
实测皮卡丘的对话片段:
请选择今天为你服务的角色:
1. 严谨理财顾问 ... 4. 皮卡丘小助手 ...
请输入选项编号: 4
============================================================
【皮卡丘小助手】 皮卡! 主人主人, 皮卡丘来啦~ 皮卡丘要帮主人数树果(钱钱)啦!
============================================================
主人主人! 告诉皮卡丘 本月总收入 (元) 是多少嘛, 皮卡~ 6000
主人主人! 告诉皮卡丘 本月预算上限 (元) 是多少嘛, 皮卡~ 4500
... (其它字段) ...
============================================================
【皮卡丘小助手】 皮卡皮卡! 皮卡丘正在认真算账, 主人等等我哦~ ⚡
============================================================
>>> 思考过程 (LangGraph ReAct, 展示 LLM 自主调度的工具链)
--- 第 1 步 --- compute_metrics ...
--- 第 2 步 --- detect_risks ...
--- 第 3 步 --- compare_history ...
🎉 Final Answer:
皮卡皮卡~! 主人, 预算状态有点紧张哦! ... 皮卡丘给你以下建议: ...
============================================================
【皮卡丘小助手】 皮卡皮卡~ 皮卡丘算好啦! 主人快来看!
============================================================
Streamlit 版可在侧边栏一键切换两种推理模式:
┌─ 单 Agent ReAct ───────────────────────┐
│ User → Advisor (ReAct + Tools) → Done │
└─────────────────────────────────────────┘
┌─ 多 Agent (Reflection) 默认 ───────────────────────────────┐
│ User │
│ ↓ │
│ Advisor (ReAct, 角色化) ── 初版建议 │
│ ↓ │
│ Auditor (财务审计员 🔍) ── 挑刺 / PASS │
│ ↓ │
│ Coordinator (协调员 🤝) ── JSON: {decision: FINISH|REVISE} │
│ ↓ │
│ REVISE → 回 Advisor (拼上 critique 让它修订) │
│ FINISH → END (终稿) │
└────────────────────────────────────────────────────────────┘
3 个 Agent 各司其职:
| Agent | 角色 | 是否用工具 | 职责 |
|---|---|---|---|
| Advisor | 用户选定的角色 (太监/皮卡丘/...) | ✅ 3 个业务工具 | ReAct 调度 + 角色化建议 |
| Auditor | 内部 auditor (🔍 财务审计员) |
❌ | 严苛挑刺, 输出问题清单或 PASS |
| Coordinator | 内部 coordinator (🤝 协调员) |
❌ | 输出 JSON {decision, reason} 决定是否再迭代 |
Auditor 与 Coordinator 也注册在同一份 personas.py 里 (带 internal=True 标志, 不出现在用户菜单),沿用项目"数据驱动 + 三处共享"的风格。
同一份输入(皮卡丘 + 已超支 + 攒进化雷之石):
初版 (advisor #1): "皮卡丘来啦~ 剩余日均预算不足 30 元..." (泛泛而谈)
↓
审计员: 5 条批评 — "冻结非必要消费没具体步骤"、"未针对超支提供方案"、"与攒进化雷之石目标不匹配"...
↓
协调员: REVISE — "建议缺乏具体性"
↓
修订 (advisor #2): "超支了 500 元、使用率 111.11%, 必须立刻冻结..." (具体可执行)
可以一眼看出修订版比初版进步:把模糊指标换成具体数字、把"冻结消费"改成"找出非必要支出项"。
所有角色集中定义在 budget_app/personas.py,两套实现共用同一份配置:
PersonaSpec(
id="eunuch", label="皇宫总管太监",
user_addr="陛下", self_addr="奴才",
personality="谦卑、机敏、察言观色",
speaking_style="半文半白, 句末多'喳'/'是'/'万岁'",
catchphrase="喳~ 奴才这就为陛下打理一二.",
system_prompt_addon="...完整人设说明..."
)新增角色只需要在 PERSONAS 字典里加一项,CLI 菜单 / 自研版 prompt / LangGraph 版 system prompt 自动同步生效,无需改任何其他代码。
| 角色 | 用户目标 | LLM 实际输出片段 |
|---|---|---|
| 太监 | 存够500两白银 | "启禀陛下,奴才已为您计算出当前内帑状况... 剩余 200 两白银... 臣奴退下,恭祝陛下财源广进,喳!" |
| 皮卡丘 | 攒进化雷之石的钱 | "皮卡丘来啦,主人!...你已经超支了... 帮助你攒钱买进化雷之石... 皮卡丘会一直支持你的,主人!" |
| 海盗船长 | 攒钱买新罗盘 | "兄弟,听我说!本船长刚刚...船舱里的金币只剩 -300 元... 这就像船底漏水... 以朗姆酒的名义起誓... 攒钱买下那把新罗盘!" |
--- 第 1 步 ---
🤔 Thought: 决定调用工具 compute_metrics (LLM 自主选择)
🎬 Action: compute_metrics({})
--- 第 2 步 ---
🤔 Thought: 决定调用工具 detect_risks (LLM 自主选择)
🎬 Action: detect_risks({})
--- 第 3 步 ---
🤔 Thought: 决定调用工具 compare_history (LLM 自主选择)
🎬 Action: compare_history({})
👀 Observation (compute_metrics): {"utilization": 92.0, "status": "紧张", ...}
👀 Observation (detect_risks): {"risk_level": "低", "warnings": []}
👀 Observation (compare_history): {"trend": "首次记录, 无历史可比", ...}
🎉 Final Answer:
1. 控制日常开支:在接下来的 12 天内, 每日支出控制在 66.67 元以内 ...
2. 优先考虑必要支出 ...
自研 hello_agents |
LangGraph 版 | |
|---|---|---|
| 依赖 | 仅标准库 | langgraph + langchain-openai |
| 调用模式 | 文本协议解析 (Thought/Action 正则) | 原生 function calling |
| 工具调度 | 单步串行 | 单轮可并行多工具 |
| 状态管理 | 手写 history list | LangGraph MessagesState |
| 可扩展性 | 适合教学演示 | 适合接入持久化、checkpoint、HITL、多 Agent |
- 自研版:仅 Python 3.9+ 标准库 (
urllib + json + re + os)。macOS 自带的/usr/bin/python3即可直接执行。 - LangGraph 版:
langgraph >= 0.2、langchain-openai >= 0.2、langchain-core >= 0.3,详见requirements.txt。