LightVela这个名字,最初只是我把Grok Bot的实时对话能力和Meta Muse式的内容创作能力拼在一起时的随口代号,但做着做着,我发现它其实代表了个人AI Agent最该有的样子——一个长期在线、有记忆、能干活、还会聊天的数字分身。如果你最近也在折腾AI Agent开发,翻过LangGraph、n8n、MCP协议这些热词,大概率也有同样的困惑:网上教程一堆,但你真正想要的那个"能一直挂在后台、随时听使唤、越用越懂我"的Agent到底怎么落地?这篇文章记录了我的完整思考过程、技术选型和踩坑记录,适合不满足于跑通demo、想把Agent真正用起来的开发者。我会从设计理念讲到工程实现,最后给出我这三个月连续运行的真实账单和翻车案例,希望你能少走点弯路。
1. LightVela要回答的问题:为什么聊天机器人总是"聊完就忘"
1.1 Grok Bot给我的启发:个性比知识更能留住人
我最早接触Grok Bot的时候,第一反应是"这玩意儿怎么这么能聊"。同样是调用大模型,很多产品给你的感觉是"一个知识库问答机器人",而Grok Bot更像一个活生生的人:它会接你的梗,会用符合你说话节奏的方式回应,会基于实时信息跟你讨论刚刚发生的事情。
后来我复盘发现,Grok Bot最值得学习的不是它的模型参数,而是它的人设工程。它的系统提示词里大概不会写"你是一个友好的助手"这种废话,而是定义了一整套语气、立场、信息获取方式。换句话说,个性不是一个附加属性,而是用户愿意持续使用的前提。
这对个人Agent意味着什么?意味着如果你的Agent每次对话都是冷冰冰的"我是AI助手,请问有什么可以帮您",用户用两次就腻了。个人Agent的黏性来自"它像我的一个朋友",而不是"它是一个工具"。我在设计LightVela的初始人设时,花了整整一个晚上反复打磨提示词,就为了让它在专业和随和之间找到一个平衡点,而不是一开口就是Office助手味。
1.2 Meta Muse代表的另一面:内容生产是"手艺活"
和Grok Bot这种对话型AI不同,Meta内部使用的写作辅助工具Muse,解决的是另一个问题:把脑子里模糊的想法变成结构化的文本资产。从公开信息来看,Muse更像一个内容工作流引擎:输入零散的brief、会议记录、随手写的想法,输出草稿、总结、结构化文档。
这个定位跟我个人的痛点完全重合。我每天有大量碎片信息——刷到的文章、冒出来的点子、项目进展——但很少有时间把它们整理成可复用的文档。普通的聊天机器人聊完就散了,不会主动帮你把这些内容沉淀下来。而这恰恰是Muse这类工具的价值:它以"产出物"为导向,而不以"对话"为导向。
所以我当时冒出来的念头很简单:能不能让一个Agent白天跟我聊天、把灵感都接住,晚上趁我睡觉的时候,把这些碎片整理成一份份干净的笔记?这就是LightVela最早的雏形。
1.3 拼起来之后,LightVela的定位才第一次清晰
Grok Bot负责"像人一样对话和获取实时信息",Muse负责"把信息变成产出物",那把这两者拼在一起会发生什么?
LightVela的定位就在这个时候清晰了。它不是一个聊天UI,而是三层结构:
- 会话层:像Grok Bot一样有性格、能闲聊、能接上下文,让交互不累。
- 工作层:像Muse一样能做内容生产,把零散输入变成结构化输出。
- 底座层:长期在线,自动调度,记忆持久化,这是前两层能成立的前提。
三句话概括就是:我睡觉的时候它还醒着,隔三天它还记得我上周提过的项目背景,早上起来它能给我一份整理好的任务清单。这就是我心中"长期在线的个人AI Agent"的及格线。低于这个标准,它跟一个带记忆的聊天机器人就没有本质区别。
2. 功能设计:一个7×24小时在线的数字分身,需要哪几层能力
2.1 感知层:从被动等待到主动唤醒
很多人设计Agent时第一反应是写一个while True循环,不断问用户"你想干什么"。但长期在线Agent的重点是:它得有主动醒来的能力。我把触发方式分成三类:
- 时间触发:每天早上九点做一次昨日总结,每周日晚生成下周计划。
- 事件触发:收到邮件、日历有新会议、GitHub仓库有新的issue或commit。
- 状态触发:某个监控指标超过阈值,比如服务器CPU跑满、某个任务卡住超过两小时。
这个设计思路其实参考了n8n的工作流节点:把Agent拆成trigger和action两部分,而不是一个把所有逻辑塞进上下文的大循环。主动唤醒的价值在于,Agent从"应答式工具"变成了"陪伴式系统",它能自己发现事情需要被处理,而不是等你开口。
这里有个细节值得说:时间触发不能只做一个cron定时器就完事。你要考虑错过触发怎么办、任务执行失败是否重试、多个任务之间是否互相依赖。LightVela的调度器会记录每次触发的执行结果,失败的任务会按指数退避策略重试最多三次,实在不行就生成一条待办放进去,由用户在第二天早上决定怎么处理。
2.2 行动层:能调工具、能写文件、能触发流程
光聊天不做事,那叫demo;做事,才叫Agent。LightVela的核心行动层我砍到最少,但每一样都真的能用:
- 文件读写:读写本地Markdown文件,这是记忆和产出物的物理载体。
- 搜索查询:调用搜索API获取实时信息,弥补模型知识截止时间的问题。
- Shell执行:执行预设脚本,比如备份笔记目录、拉取最新代码。
- Webhook触发:通过HTTP请求调用其他服务的接口,比如往企业微信或Telegram发通知。
每个行动都被包装成独立的tool,有明确的输入输出格式。模型在做规划时看到的是"有哪些工具、每个工具怎么用",而不是一段模糊的函数调用描述。这个设计有一个怎么强调都不为过的原则:工具的边界要小,职责要单一。比如文件工具拆成read_file和write_file两个,而不是一个万能的file_operation。工具描述越精准,模型调错的概率越低。
2.3 记忆层:短期、长期、项目三份记忆各管各的
记忆是"长期在线"的灵魂。我踩过很多坑之后,把记忆设计成三层:
- 短期记忆:当前对话窗口,直接塞进system prompt。优点是即时生效,缺点是上下文有限。
- 长期偏好档案:一个JSON文件,记录用户的固定偏好,比如"写代码时用Python优先""每天九点要简报""不要用敬语"。每条记录带有时间和来源,可以被更新或删除。
- 项目记忆:按项目分目录的Markdown笔记,记录关键决策、进展、坑。Agent在做项目相关任务时按需读取对应目录。
有人会问:不用向量数据库做语义检索吗?我的回答是:个人Agent的场景里,结构化的小记忆比海量语义检索更实在。我还没有到需要检索数千条笔记的规模,一个SQLite加上文件系统已经够用,而且可读、可改、可审计。你打开数据库就能看到Agent到底记住了你什么,这一点在建立信任上非常重要。
我在记忆写入上还加了一层"重要性过滤":不是所有对话内容都值得长期记住。模型在每次对话结束时,会先判断哪些信息满足"稳定的用户偏好、正在进行的关键任务、明确的项目决策"这三个条件之一,只有满足条件的才写入长期记忆。这让记忆库保持了干净,避免了大量噪声。
3. 长期在线的技术骨架:四个绕不开的工程决策
3.1 状态管理:没有持久状态就没有"长期"可言
如果你做过Web服务,应该知道"无状态"是分布式系统的基本假设。但Agent恰恰相反,它天生是有状态的:它是谁、记住了什么、进行到哪个任务、下一步该做什么。长期在线的Agent,必须把状态显式地持久化,而不是依赖进程内存。
我的方案是:把Agent的状态拆成两份。一份是"对话状态",记录当前会话的上下文压缩摘要;另一份是"任务状态",记录每个长期任务的进度、依赖和结果。两份都落到SQLite。这样Agent进程崩溃了、机器重启了,它还能从上次的状态恢复,而不是一脸茫然地重新开始。
这一点在AI Agent相关的技术面试里也是个高频问题:如果让你设计一个生产级Agent,你会怎么处理状态?标准的答法就是"外部化状态、事件溯源、幂等恢复",LightVela用最朴素的方式把这三件事都做了:SQLite存状态,操作日志做溯源,任务表加唯一约束做幂等。
3.2 任务调度:把"随时响应"变成可执行的队列
长期在线意味着Agent要同时处理多件事:定时简报、邮件提醒、用户随时发来的对话请求。如果所有逻辑都挤在一个入口,很快就会互相阻塞。我用了最简单的调度模型:一个任务队列加一个工作线程池。
队列里每条任务带上类型、优先级、调度规则、载荷。定时任务由调度器负责往队列里投递,用户的即时消息也有单独的优先级通道。实测下来,这个模型够用了,不需要一开始就上Celery或专门的分布式调度器。等任务量真的大到单机扛不住,再考虑迁移也不迟。
调度这块我吃过一个亏:一开始把定时任务挂在主进程里,用Python的asyncio.sleep做延时,结果Agent进程一重启,所有定时任务全部丢失。后来改成把调度规则和下次执行时间都存进数据库,启动时扫描一次数据库恢复所有任务,这才真正做到了"长期"。
3.3 工具协议:MCP比自研插件更值得投入
关于工具接入,我经历了三个阶段。第一阶段是给每个工具写自己的调用函数,结果工具一多,注册逻辑乱成一团。第二阶段我改用MCP协议,把工具定义成标准化的server,Agent通过协议去发现和调用工具。
MCP的好处一是标准化,一个工具写好了,任何支持MCP的客户端都能用;二是隔离,工具运行的权限、错误处理、超时控制都跟Agent主进程分开。虽然MCP本身还在快速演进,配置上也有不少坑,但方向是对的。如果你现在刚开始做一个会调工具的Agent,我建议直接按MCP协议来设计,省得以后返工。
举个具体的例子,给LightVela加一个"查询天气"的工具,如果走MCP,我只需要写一个独立的server,声明工具名、描述、输入输出schema,然后在配置文件里注册一下。主程序不用改一行代码。这个插件化的思路,让Agent的扩展成本降到了极低。
3.4 模型路由:简单对话和深度任务分开用模型
长期在线Agent的另一个现实问题是成本。如果每一条消息、每一次定时触发都调用最强的模型,一个月下来账单会非常难看。我做了简单的模型路由:
| 任务类型 | 模型档次 | 原因 |
|---|---|---|
| 闲聊、打招呼、意图判断 | 快模型 | 反应快、成本低,不需要太强推理 |
| 内容总结、任务规划 | 中档模型 | 需要一定推理能力但不用顶配 |
| 代码生成、长文档深加工 | 强模型 | 质量优先,接受更高成本 |
模型路由不是简单if-else,而是在Agent的规划阶段就由路由层决定:这条任务要不要复杂推理?是否需要长上下文?然后选择对应的模型和上下文策略。这一步做好了,成本能省至少40%。
路由层还有一个隐藏的好处:它可以把不同类型的任务分流到不同的上下文环境里。比如编程任务有编程专用的上下文,写作任务有写作专用的上下文,互不污染。这和后面要讲的多Agent思路是一个雏形。
4. 从零搭建LightVela:一套可复现的最小实现
4.1 技术选型与目录结构
我最终用的技术栈是Python + LangGraph + SQLite + Docker。选LangGraph不是因为赶时髦,而是它把Agent的节点、边、状态机模型已经抽象好了,省去自己维护图状态的工作量。如果你更熟悉JS生态,也可以用LangChain.js或者自己手写状态机,核心思路一样。
目录结构是这样的:
lightvela/ ├── agent/ │ ├── core.py # Agent主循环 │ ├── router.py # 模型路由 │ └── prompt.py # 人设与系统提示词 ├── memory/ │ ├── short_term.py # 短期上下文 │ ├── profile.py # 长期偏好档案 │ └── project.py # 项目记忆 ├── tools/ │ ├── file_tool.py # 文件读写 │ ├── search_tool.py # 搜索 │ ├── shell_tool.py # shell执行 │ └── webhook_tool.py # webhook通知 ├── scheduler/ │ ├── queue.py # 任务队列 │ └── triggers.py # 定时与事件触发器 ├── data/ # SQLite和markdown存放目录 └── docker-compose.yml这个目录的核心原则是:agent只负责决策,memory负责记忆,tools负责执行,scheduler负责唤醒。四者之间通过数据结构和消息队列通信,尽量不互相import。这样每个模块都可以独立测试、独立替换。
4.2 核心代码:主循环、工具注册与记忆写入
Agent主循环用LangGraph来实现,核心就是一个有限的图:接收消息、路由模型、调用工具、写入记忆、返回结果。关键的代码片段如下:
# agent/core.py - 简化版Agent主循环 from langgraph.graph import StateGraph, END from typing import TypedDict class AgentState(TypedDict): messages: list task_type: str tool_calls: list tool_results: list def route_model(state: AgentState): # 根据任务类型选择模型 task_type = state["task_type"] if task_type == "chat": return {"model": "fast-model"} elif task_type == "deep": return {"model": "strong-model"} return {"model": "mid-model"} def call_tools(state: AgentState): results = [] for call in state["tool_calls"]: result = tools_registry[call["name"]](**call["args"]) results.append({"name": call["name"], "result": result}) return {"tool_results": results} def write_memory(state: AgentState): # 对话结束后,把重要信息写入长期档案 important = extract_facts(state["messages"]) memory.profile.append(important) return {"memory_write": "ok"} graph = StateGraph(AgentState) graph.add_node("route", route_model) graph.add_node("tools", call_tools) graph.add_node("memory", write_memory) graph.set_entry_point("route") graph.add_edge("route", "tools") graph.add_edge("tools", "memory") graph.add_edge("memory", END)工具注册按照MCP协议的标准来做,每个工具都需要提供name、description、input_schema。以搜索工具为例:
{ "name": "web_search", "description": "搜索公开网页信息,返回前N条结果摘要。适合查询实时新闻、文档、技术资料。", "inputSchema": { "type": "object", "properties": { "query": {"type": "string", "description": "搜索关键词"}, "limit": {"type": "integer", "default": 5} }, "required": ["query"] } }描述写清楚"适合查询实时新闻、技术资料"是有讲究的。模型根据描述决定要不要调用这个工具,描述越具体,误调用的概率越低。我见过很多人写工具描述只写一句"搜索",结果模型在不需要搜索的时候也去搜索,既浪费token又污染上下文。
4.3 如何验证它真的"长期在线"
跑通代码只是第一步,验证"长期在线"要用三个测试:
- 重启恢复测试:杀掉进程、重启容器,确认Agent能从SQLite恢复所有未完成任务。
- 跨天记忆测试:今天告诉它"我下周要做一个电商项目",一周后问它"还记得那个项目的背景吗",它应该能答上来。
- 定时唤醒测试:设置一个每天九点的简报任务,连续观察三天,确认它每天准点执行。
这三个测试我建议写成自动化的shell脚本,每次改完代码都跑一遍。验证这件事如果靠手动,早晚会漏。
5. 连续运行三个月:效果、账单与翻车记录
5.1 真正让我觉得"值了"的场景
连续跑了三个月,最值的场景有两类。第一类是"晨间简报+任务整理",我每天早上打开电脑,Agent已经把所有项目进展、待办事项按优先级排好;第二类是"碎片信息沉淀",我在手机上随手发一段语音或链接给它,它会自动整理成带标题、标签、关联项目的笔记,并主动补上相关背景。
说实话,这两件事单独看都不算惊艳,但叠加"长期在线"这个属性后,体验完全不一样——它像是一个从来不休息的私人助理,把那些"想到了但没时间做"的事全部接住了。以前我用各种笔记软件,核心问题是采集容易、整理难;现在LightVela自动完成了整理这一环,我的笔记系统才真正转起来。
5.2 成本账单:token比想象中烧得快
直接说数字。我的模型路由配置下,日均token消耗在120万到200万之间,其中约60%来自定时任务和后台归纳,只有40%来自我主动发起的对话。月账单折算下来大约在30到60美元之间,取决于当月的任务密度。
这个成本结构是很多人没预料到的。你以为聊天是花钱的大头,其实是后台的定时总结、记忆归纳、上下文重压缩在烧钱。优化方向也很明确:降低定时任务频率、压缩长上下文、尽量用快模型做归纳。我现在把晨间简报的生成模型从中档降到了快模型,单这一项每月就能省七八美元,而且摘要质量几乎没变化。
5.3 三个翻车案例和修复过程
案例一:记忆污染。Agent把一次文件夹扫描的结果误写进了长期偏好档案,导致后续所有对话都默认"用户喜欢把所有文件都整理到这个目录"。修复是给记忆写入加了一个过滤层,只有模型判断为"稳定的用户偏好"时才能写入。
案例二:工具调用死循环。某次搜索返回了大量无关结果,Agent为了修正自己的答案,连续调了七次搜索接口,最后把上下文撑爆了。修复是在主循环里加了工具调用次数上限,超过三次就停止尝试,直接给出"信息不足"的结论。
案例三:定时任务重复执行。Docker容器重启后,同一个定时任务被重复投递了三次,导致三份重复的简报。修复是将任务执行记录也持久化到SQLite,并在投递前做幂等检查。
这三个坑,其实都不是模型不够强,而是工程问题——记忆的写权限控制、工具调用的边界、任务调度的幂等性。做Agent,工程严谨性比模型选型更决定成败。这也是为什么我一直跟朋友说,想做Agent先补工程基础,别一上来就追最强的模型。
6. 如果再做一个LightVela 2.0,我会改这些设计
6.1 从单个Agent走向多Agent协作
现在LightVela是单Agent架构,所有事情都交给一个大脑。它的弱点在上下文轮换和角色冲突:又要写代码又要整理笔记又要闲聊,一个上下文很容易互相干扰。如果要重做,我会拆成多个专职Agent,比如编程Agent、写作Agent、信息整理Agent,再用一个或chestrator做路由。这也是Spring AI Multi Agent、LangGraph这类框架最近讨论最热的模式。
多Agent不是堆Agent数量,而是让每个Agent有一个非常窄的职责边界。编程Agent只需要关心代码库,写作Agent只需要关心文档。它们之间通过消息总线传递结果,而不是共享同一个上下文。这样既能降低单次调用的上下文压力,又能让每个Agent的人设更加统一。
6.2 本地模型兜底、云端模型补强
隐私敏感的数据,我现在只能手动规避——不把私人内容发给云端模型。LightVela 2.0我会做一个本地优先的设计:所有记忆和文件处理先过本地的小模型,只有需要强推理或生成的时候才走云端。这样即使将来云端接口涨价或不可用,核心的"长期在线"能力也不会瘫痪。
这个思路跟"内网本地AI Agent免费"这类需求完全吻合。现在本地模型在指令跟随和代码能力上已经进步很多,特别是量化后的7B到14B模型,做意图判断、内容分类、格式整理这类活完全够用。云端模型只处理最重的推理任务,成本和安全问题都会被压到最低。
6.3 给还没入坑的朋友的三条实在建议
第一条,别一上来就追求复杂。先把"一个会调工具的聊天机器人"跑通,再逐步加记忆、加调度、加多Agent。第二条,记忆设计从结构化开始,不要上来就上向量库,JSON加SQLite能解决个人场景90%的问题。第三条,把成本观测和幂等控制当成基础设施,而不是后补的优化项。
我做LightVela这几个月最大的体会是:AI Agent的真正门槛不在模型,而在工程。模型是把"对话能力"做出来的,而工程是把"长期在线"这四个字做出来的。今天这个项目还远谈不上完美,但它已经让我的日常效率有了肉眼可见的提升——这就够了。后面我会继续迭代,有了新的进展再回来分享。