
我一直对个人开发者如今能快速推出实用的原型产品感到惊讶。
像Claude Code、Google AntiGravity以及围绕它们发展的生态系统,已经跨越了一个临界点:你可以在网上查看其他人正在构建的项目,然后意识到如今的开发速度有多快。
在过去几周里,我开始每天专门预留1到2小时,使用我的AI优先技术栈进行开发:
Google AntiGravity
Google Gemini Pro
通过AntiGravity访问的Claude模型
这套技术栈从根本上改变了我对原型开发、迭代速度以及“个人AI智能体”实际能力的认知。更重要的是,它让我重新投入到手写代码和实际开发中——自从我在DareData的角色从执行转向管理和协调后,我就个人放弃了这些工作。
就个人而言,这场变革对那些注定会走向管理岗位的人来说是一种福音。它消除了我曾经接受的权衡:发展公司意味着完全放弃开发。我不再需要在开发和管理之间做选择,它们实际上是相互促进的。
但对于那些“仅仅”专注于开发的人来说,这还有更广泛的影响。如果AI智能体越来越多地承担执行工作,那么单纯的实现能力就不再足够。开发者将被迫(无论他们愿意与否)转向协调、决策和……管理——这是很多独立贡献者从心底里厌恶的事情。换句话说,管理技能已成为技术栈的一部分,而AI智能体则是被管理的对象之一。
最让我惊讶的是,我现有的管理技能竟然具有如此高的可迁移性:
引导智能体,而非微观管理它
要求结果,而非下达具体指令
梳理、排序任务,并指出模糊不清的领域
实际上,我正在管理和协调一名虚拟员工。我可以深入影响它工作的某些部分,同时对其他部分几乎一无所知——这不是缺陷,而是一个重要特性。例如,在我的个人AI助手的开发中,我对后端逻辑非常清楚,但对前端却几乎一窍不通。但系统依然能正常运行,因为我的角色不再是无所不知,而是引导系统朝着正确的方向发展。
这与我在公司内部协调人员的方式非常相似。随着DareData的发展,我们不会招聘创始人的复制品。我们特意招聘那些能做我们做不到的事情的人,而且随着时间的推移,他们会做一些我们永远无法深入学习并做好的事情。

关于管理的自我反思就到此为止。让我们来看看我正在构建的项目——这才是你们来这里的目的:
一个围绕我实际日常流程设计的个人AI助手,而非通用的生产力模板。它能适应我的工作方式、思维模式和决策习惯。
一个每周推荐一张音乐专辑的移动应用,不使用传统的推荐系统。它不会强化我的舒适区,有助于我拓展音乐聆听范围。
一个围绕单个角色在分层地牢中推进的移动游戏,开发它主要是为了打造一个创意游乐场,而非商业产品。
有趣的是,虽然我很擅长编写大部分后端代码,但前端开发并不是我的技能——如果被迫自己做前端,这些项目的进度会从几小时放缓到几天,甚至可能永远无法完成。
现在,这个限制在很大程度上已经无关紧要了。有了这套新的技术栈,想象力成了真正的瓶颈。“不懂”某一整个技术层的成本已经大幅降低。
因此,在本文的其余部分,我将详细介绍我的个人AI助手:它的功能、结构,以及为什么它适合我。我的目标是在它稳定后开源,让其他人可以根据自己的工作流程进行调整。目前它非常贴合我的个人生活,但这种特异性是有意为之,而使其更通用则是实验的一部分。
认识费尔南奥(Fernão)
费尔南奥·洛佩斯(Fernão Lopes)是葡萄牙君主制的编年史家。我特意选择了一位葡萄牙历史人物——葡萄牙人有一个习惯,几乎会给所有东西起一个历史名字。如果这听起来很有葡萄牙特色,那正是我的用意。
费尔南奥是葡萄牙人,但实际上说英语,可以称他为21世纪的现代编年史家。

目前,我正在做两件我通常会避免的事情:将AI拟人化,以及迎合葡萄牙人给事物命名的本能。就当是我年纪渐长的一个无害标志吧。
除此之外,费尔南奥实际上能为我做什么?最好的切入点是它的主页。

费尔南奥这个“酷家伙”目前负责五项任务:
每日日程(Day Schedule):整合日历、待办事项和目标,为我制定可执行的每日计划。
写作助手(Writing Assistant):帮助我审阅和修改博客文章及其他文本的初稿。
投资组合助手(Portfolio Helper):根据资产再平衡需求和宏观市场动态,建议可添加的公司股票或交易所交易基金(ETF)(不冒充预测未来的“水晶球”)。
财务整理员(Financial Organizer):从我的银行对账单中提取支出信息,并将所有内容上传到Cashew应用程序,为我节省了每月约3到4小时的时间。
订阅与折扣(Subsc riptions & Discounts):跟踪我所有的订阅服务,并提醒我那些可能拥有但从未记得使用的折扣或福利。
在本文中,我将重点介绍每日日程应用。
目前,费尔南奥的每日日程主要做三件简单的事情:
获取我的日历,包括所有已安排的会议
从Microsoft To Do中提取我的待办事项(注:文档中关联的Microsoft To Do相关网页https://login.microsoftonline.com/consumers、https://graph.microsoft.com/v1.0/me/todo/lists、*https://graph.microsoft.com/v1.0/me/todo/lists/*均解析失败,无法获取网页具体内容,以下内容基于文章中的代码和描述展开)
从Notion中获取我的个人关键成果
所有这些都通过API连接。核心思路很简单:每天,费尔南奥查看我的约束条件、优先事项和承诺,然后为我生成最佳的日程计划。

在前端生成日程计划非常简单(所有前端都是“氛围编码”完成的)。以下是生成日程的按钮:

一旦我点击“生成日程”,费尔南奥就会在后台开始工作:

具体步骤如下(按顺序):获取日历、任务和Notion数据。
接下来这一点也正是基础编码能力真正发挥作用的地方——不是因为下面的代码无法运行,而是因为你需要理解正在发生的事情,以及哪里可能出现故障或需要改进。
我们先从日历获取开始。目前,这由Claude生成的一个庞大且完全未优化的函数处理。
def get_events_for_date(target_date=None):
"""
通过ICS订阅源从Google日历获取特定日期的事件。
参数:
target_date: 目标日期的datetime.date对象。如果为None,则使用今天。
返回: 事件字典列表。
"""
# 硬编码日历URL(不使用环境变量以避免占位符问题)
CALENDAR_URLS = [
'cal1url',
'call2url'
]
LOCAL_TZ = os.getenv('TIMEZONE', 'Europe/Lisbon')
# 获取时区
local = tz.gettz(LOCAL_TZ)
# 如果未提供目标日期,则使用今天
if target_date is None:
target_date = datetime.now(local).date()
# 创建目标日期的时间边界
day_start = datetime.combine(target_date, datetime.min.time()).replace(tzinfo=local)
day_end = day_start + timedelta(days=1)
# 调试:打印我们正在检查的日期范围
print(f"\n[Debug] Checking calendars for date: {target_date.strftime('%Y-%m-%d')}")
print(f" Start: {day_start.strftime('%Y-%m-%d %H:%M %Z')}")
print(f" End: {day_end.strftime('%Y-%m-%d %H:%M %Z')}")
print(f" Timezone: {LOCAL_TZ}")
all_events = []
# 从每个日历获取事件
for idx, cal_url in enumerate(CALENDAR_URLS, 1):
calendar_name = f"Calendar {idx}"
print(f"\n[Debug] Fetching {calendar_name}...")
try:
# 从ICS URL加载日历,设置足够的超时时间
r = requests.get(cal_url, timeout=30)
r.raise_for_status()
cal = Calendar(r.text)
events_found_this_cal = 0
total_events_in_cal = len(list(cal.events))
print(f" Total events in {calendar_name}: {total_events_in_cal}")
# 使用时间线高效筛选目标日期范围内的事件
# 将本地时间转换为UTC用于时间线筛选
day_start_utc = day_start.astimezone(timezone.utc)
day_end_utc = day_end.astimezone(timezone.utc)
# 获取目标日期范围内的事件(使用时间线)
days_timeline = cal.timeline.overlapping(day_start_utc, day_end_utc)
for e in days_timeline:
if not e.begin:
continue
# 获取事件开始时间
start = e.begin.datetime
if start.tzinfo is None:
start = start.replace(tzinfo=timezone.utc)
# 转换为本地时区
start_local = start.astimezone(local)
# 调试:打印前几个事件以查看日期
if events_found_this_cal < 3:
print(f" Event: '{e.name}' at {start_local.strftime('%Y-%m-%d %H:%M')}")
# 获取结束时间
end = e.end.datetime if e.end else None
end_local = end.astimezone(local) if end else None
all_events.append({
"title": e.name,
"start": start_local.strftime("%H:%M"),
"end": end_local.strftime("%H:%M") if end_local else None,
"location": e.location or "",
"desc ription": e.desc ription or ""
})
events_found_this_cal += 1
print(f" [OK] Found {events_found_this_cal} event(s) for target day in {calendar_name}")
except requests.exceptions.RequestException as e:
print(f" [X] Network error fetching {calendar_name}: {str(e)}")
continue
except Exception as e:
print(f" [X] Error processing {calendar_name}: {type(e).__name__}: {str(e)}")
continue
# 按开始时间排序
all_events.sort(key=lambda x: x["start"])
# 详细打印所有事件
if all_events:
print(f"\n[Google Calendar] Found {len(all_events)} event(s) for {target_date.strftime('%Y-%m-%d')}:")
print("-" * 60)
for event in all_events:
time_str = f"{event['start']}-{event['end']}" if event['end'] else event['start']
location_str = f" @ {event['location']}" if event['location'] else ""
print(f" {time_str} | {event['title']}{location_str}")
print("-" * 60)
else:
print(f"\n[Google Calendar] No events for {target_date.strftime('%Y-%m-%d')}")
return all_events
作为一名Python开发者,所有的打印语句都让我感到不适。但这是费尔南奥下一阶段的问题:一旦产品逻辑稳定,就对代码进行重构和优化。
这也正是我真正看到人类与AI协同工作的优势所在。我能立即发现优化这个函数的几种方法(减少冗余、降低不必要的延迟、梳理流程),但要做好这些仍然需要时间、判断力和明确的目标。AI帮助我快速推进,但它无法替代我对“卓越”的判断。
目前,我还没有花太多时间优化它,这是一个有意识的选择。尽管它有很多粗糙的地方,但这个函数完全实现了我需要的功能:从我的日历中提取数据,并将会议信息提供给费尔南奥,为后续所有操作奠定基础。
接下来,费尔南奥从Microsoft To Do中提取我的任务。我的每日待办事项(那些需要完成的具体小事,它们构成了特定一天的结构)都存放在这里。所有这些都直接在Microsoft To Do应用中配置,这是我日常工作流程的核心部分。
如果你对这背后更广泛的生产力系统感兴趣,我在这个博客的姐妹博客(Wait a Day)中写过相关文章,链接如下。
下面,我们来看另一个冗长的函数:
def get_tasks(target_date=None):
"""
从Microsoft To Do获取特定日期的任务(截止日期为该日期或之前的任务)。
参数:
target_date: 目标日期的datetime.date对象。如果为None,则使用今天。
返回: 任务字典列表。
"""
CLIENT_ID = os.getenv('MS_CLIENT_ID', 'CLIENT_ID_KEY')
AUTHORITY = "https://login.microsoftonline.com/consumers"
SCOPES = ['Tasks.ReadWrite', 'User.Read']
# 设置持久化令牌缓存
cache = SerializableTokenCache()
cache_file = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), '.token_cache.bin')
if os.path.exists(cache_file):
with open(cache_file, 'r') as f:
cache.deserialize(f.read())
# 使用持久化缓存进行身份验证
app = PublicClientApplication(CLIENT_ID, authority=AUTHORITY, token_cache=cache)
accounts = app.get_accounts()
result = None
if accounts:
result = app.acquire_token_silent(SCOPES, account=accounts[0])
if not result or "access_token" not in result:
for account in accounts:
app.remove_account(account)
result = None
if not result:
flow = app.initiate_device_flow(scopes=SCOPES)
if "user_code" not in flow:
print(f"[MS To Do] Failed to create device flow: {flow.get('error_desc ription', 'Unknown error')}")
return []
if "message" in flow:
print(flow['message'])
result = app.acquire_token_by_device_flow(flow)
if not result or "access_token" not in result:
print(f"[MS To Do] Authentication failed: {result.get('error_desc ription', 'No access token') if result else 'No result'}")
return []
headers = {"Authorization": f"Bearer {result['access_token']}"}
# 获取目标日期的时间边界
# 如果未提供目标日期,则使用今天
if target_date is None:
from datetime import date
target_date = date.today()
# 将日期转换为UTC时间用于比较
now = datetime.now(timezone.utc)
target_day_end = datetime.combine(target_date, datetime.max.time()).replace(tzinfo=timezone.utc)
# 获取所有任务列表
lists_r = requests.get("https://graph.microsoft.com/v1.0/me/todo/lists", headers=headers)
if lists_r.status_code != 200:
return []
lists_res = lists_r.json().get("value", [])
all_tasks = []
# 从所有列表中获取任务(服务器端过滤)
for task_list in lists_res:
list_id = task_list["id"]
list_name = task_list["displayName"]
# 简单过滤——只获取未完成的任务
params = {"$filter": "status ne 'completed'"}
tasks_r = requests.get(
f"https://graph.microsoft.com/v1.0/me/todo/lists/{list_id}/tasks",
headers=headers,
params=params
)
if tasks_r.status_code != 200:
continue
tasks = tasks_r.json().get("value", [])
# 过滤并转换任务
for task in tasks:
due_date_obj = task.get("dueDateTime")
if not due_date_obj:
continue
due_date_str = due_date_obj.get("dateTime")
if not due_date_str:
continue
try:
due_date = datetime.fromisoformat(due_date_str.split('.')[0])
if due_date.tzinfo is None:
due_date = due_date.replace(tzinfo=timezone.utc)
# 包含所有截止日期为目标日期或之前的任务
if due_date <= target_day_end:
# 根据目标日期确定状态
target_day_start = datetime.combine(target_date, datetime.min.time()).replace(tzinfo=timezone.utc)
if due_date < target_day_start:
status = "OVERDUE"
elif due_date <= target_day_end:
status = f"DUE {target_date.strftime('%Y-%m-%d')}"
else:
status = "FUTURE"
all_tasks.append({
"list": list_name,
"title": task["title"],
"due": due_date.strftime("%Y-%m-%d"),
"importance": task.get("importance", "normal"),
"status": status
})
except Exception as e:
continue
# 打印任务摘要
if all_tasks:
print(f"[MS To Do] {len(all_tasks)} task(s) for {target_date.strftime('%Y-%m-%d')} or overdue")
else:
print(f"[MS To Do] No tasks due on {target_date.strftime('%Y-%m-%d')} or overdue")
# 保存令牌缓存供下次运行使用
if cache.has_state_changed:
with open(cache_file, 'w') as f:
f.write(cache.serialize())
return all_tasks
这个函数会获取我当天的所有任务(以及前几天逾期未完成的任务)——以下是它们在待办应用中的示例:

从待办应用中获取任务后,我还希望费尔南奥了解我的长期目标,而不仅仅是当天的任务清单。为此,它会直接从Notion页面获取我的目标,我在该页面中记录了本年度的关键成果。
以下是这些目标的结构示例:
第一列显示我年初的基准状态,
最后一列定义我想要达成的目标,
右侧一列跟踪我的当前进度。
下面的示例包括我今年想为你们写的博客文章数量,以及我三本书的总销量目标。
这让费尔南奥能够了解任务的优先级背景,你将在生成日程的提示词中看到这一点。

顺便说一句,在写这篇文章的时候,我给应用添加了一个小部件。既然我们在构建个人助手,不妨让它多一些个性。
于是我问Gemini:
“你能在应用获取日历事件、检查待办事项和提取Notion数据时添加一个有趣的动画吗?比如一个费尔南奥搅拌锅的小部件,配上标题‘费尔南奥正在忙碌中(Fernão is cooking)’。”

这一轮操作完成后,任务和日历事件会被成功收集并显示在费尔南奥的前端(以下是我当天任务和会议的示例)。

现在到了最有趣的部分:有了日历、任务和目标,费尔南奥将我的一整天整合为一个完整、实用的计划:
07:30-09:30 | 健身
09:30-09:40 | 在Odoo上检查工时表(截止日期:2026-02-04)
09:40-09:55 | 审阅待办事项中的任务 - [组织类任务](截止日期:2026-02-04)
09:55-10:15 | 阅读Feedly内容 - [新闻汇总](截止日期:2026-02-04)
10:15-10:30 | 撰写文化文档,灵感来源:https://pt.slideshare.net/slideshow/culture-1798664/1798664(注:该网页解析失败,无法获取具体内容)(截止日期:2026-02-04)
10:30-10:45 | 回复领英消息 - [组织类任务](截止日期:2026-02-04)
10:45-11:00 | 检查Looker(截止日期:2026-02-04)
11:00-11:30 | 本周AI专栏文章(截止日期:2026-02-04)
11:30-12:00 | 准备播客《解码AI》
12:00-13:00 | 播客《解码AI》- 伊沃·贝尔纳多,DareData(会议)
13:00-14:00 | 午休
14:00-14:30 | 候选人1(姓名隐藏)与伊沃·贝尔纳多 @ Google Meet(会议)
14:30-18:00 | 准备DareData年度状态报告
18:00-18:30 | 候选人2(姓名隐藏)与伊沃·贝尔纳多 @ Google Meet(会议)
18:30-19:00 | 候选人3(姓名隐藏)与伊沃·贝尔纳多 @ Google Meet(会议)
19:00-19:30 | 候选人4(姓名隐藏)与伊沃·贝尔纳多 @ Google Meet(会议)
19:30-20:00 | 候选人5(姓名隐藏)与伊沃·贝尔纳多 @ Google Meet(会议)
20:00-20:15 | 查看内部交易信号以获取股票灵感 https://finviz.com/insidertrading?tc=1(注:该网页字数超限,无法完整解析)(逾期)
20:15-20:30 | 营销时间线(逾期)
20:30-21:00 | 晚餐休息
21:00-22:00 | 阅读(葡萄牙语“Ler”)
22:00-22:15 | 结束一天 - 回顾并准备明天
这是一个真正让人感到“神奇”的时刻。不是因为技术晦涩难懂,而是因为结果非常简洁。一堆杂乱的会议、任务和长期目标,变成了我可以实际执行的一天。
更有趣的是,最后一步竟然如此简单。在后台完成所有繁重的工作(获取日历事件、待办事项、目标)后,我不需要编排复杂的流水线或提示词链。我只使用一个提示词。
这个提示词整合了费尔南奥所知道的关于我的所有约束条件和优先事项,并将其转化为你即将看到的日程。
name: daily_schedule
desc ription: Generate a daily schedule based on calendar events and tasks
model: gemini-2.5-flash-lite
temperature: 0.3
max_tokens: 8192
variables:
- date_context
- events_str
- tasks_str
- context
- todo_context
- auto_context
- currently_reading
- notion_context
- is_today
template: |
You are my personal AI scheduling assistant. Help me plan my day!
**TARGET DATE:** Planning for {date_context}
**EVENTS (Fixed):**
{events_str}
**TASKS TO SCHEDULE:**
{tasks_str}
**MY CONTEXT:**
{context}
**TASK CONTEXT (how long tasks typically take):**
{todo_context}
**AUTO-LEARNED CONTEXT:**
{auto_context}
**CURRENTLY READING:**
{currently_reading}
**RESULTS & ob jectIVES (from Notion):**
{notion_context}
**SCHEDULING RULES:**
1. **Cannot schedule tasks during calendar events** - events are fixed
2. **Mandatory breaks:**
- Lunch: 12:30-13:30 (reserve when possible)
- Dinner: 20:30-21:00
- Playing with my cat: 45-60 minutes somewhere scattered around the day
3. **Task fitting:** Intelligently fit tasks between events based on available time
4. **Time estimates:** Use the task context to estimate how long each task will take
5. **Working hours:** 09:30 to 22:00
6. **Start the schedule:** {is_today}
**YOUR JOB:**
1. Create a complete hourly schedule for {date_context}
2. Fit all tasks between events and breaks
3. **Prioritize tasks based on my Results & ob jectives from Notion** - focus on what matters most
4. Be conversational - if you need more info about a task, ask me!
5. **Save learnings:** If I give you context about tasks, acknowledge it and say you'll remember it
**FORMAT:**
Start with a friendly greeting, then provide the schedule in this format:
09:30-10:00 | Task/Event 10:00-11:00 | Task/Event ...
After the schedule, ask if I need any adjustments or if you need clarification on any tasks.
Generate my day's schedule now, thanks!
有了这个提示词,费尔南奥真的在“忙碌起来”了:

构建这个系统真的非常有趣。我会继续完善费尔南奥,赋予它新的职责,发现问题、解决问题,并在这里分享我一路上的收获。
随着时间的推移,我还计划撰写实用教程,教大家如何自己构建和部署类似的应用。目前,费尔南奥只在我的设备上运行,这种情况可能还会持续一段时间。不过,我确实打算将它开源。不是因为它目前的形式具有普遍适用性(它深深贴合我的个人生活),而是因为它背后的理念可能对其他人有用。
为了实现这一点,我需要抽象工具、模块化功能,并允许开启或关闭某些特性,这样其他人就可以围绕自己的工作流程打造助手,而不是被迫适应我的流程。
我本可以仅使用Claude Code构建类似的东西,但我没有这样做。我想要完全的控制权:自由切换模型、混合不同的提供商,最终让费尔南奥运行在本地LLM上,而不是依赖外部API。在这里,所有权和灵活性比便利性对我来说更重要。
如果你要构建一个个人AI助手,你会让它承担哪些任务?我真的很想听听你的想法,并尝试在费尔南奥中实现它们。请留下评论——这个项目仍在不断发展,外部视角往往是让它快速完善的最佳方式。
推荐学习书籍 《CDA一级教材》适合CDA一级考生备考,也适合业务及数据分析岗位的从业者提升自我。完整电子版已上线CDA网校,累计已有10万+在读~ !



雷达卡





京公网安备 11010802022788号







