创造更好的学习搜索体验
继续我的努力来构建项目和有用的工具,我们将深入探讨一些重要主题,通过构建一个更好的类似Perplexity的回答引擎(在这个案例中,是一个学习引擎),使用DeepSeek和OpenAI的推理模型(o3和r1)来为应用程序,并利用AI代理来丰富内容。
首先,让我们来界定这个问题。当困惑出现的时候,利用AI辅助搜索才刚刚起步。很快,我们开始看到许多竞争对手的产品,比如谷歌搜索的AI摘要和必应的副驾。甚至像OpenAI这样的AI公司也开始涉足AI搜索领域。我时有时无地使用过这些工具,但对这些工具在学习新事物上的不足感到失望。我总是发现自己去维基百科来理解一个主题。这让我开始思考,为什么我会这样做。
所以我转向了OpenAI的O1模型来解决这个问题。它对上述现象提供了一个相当有说服力的论证,详情请见此处 https://chatgpt.com/share/67985682-38d4-8005-9466-6a0c008f7308,
下面是一个简短的版本:
研究显示,人类在时间顺序的信息呈现时学习效果更佳,这主要是因为这与我们自然而然地将事件分段并按顺序回忆的倾向相吻合(Mandler & Johnson, 1977; Zacks & Tversky, 2001)。时间顺序讲故事可以减少认知负荷,提供一个连贯的结构,使我们更容易组织和检索信息(Sweller, 1988)。它还利用了时间相近的事件联系起来的倾向(Howard & Kahana, 1999),并通过叙事流强调因果关系,增加参与感(Green & Brock, 2000)。
让我再把它简化一点。我们的大脑,就像大语言模型一样(你知道这挺讽刺的,因为我们又回到了起点),依赖于上下文线索和“时间戳”来存储和检索信息。这就是为什么维基百科总是吸引我并让我每年捐赠;)
(注:“大语言模型”是“LLMs”的翻译。)
这鼓励了我开始思考建立一个更实用的搜索引擎,专注于学习相关主题。
如果有专门为帮助你学习而设计的搜索引擎会怎样?
- 它会收集关于该主题的相关信息,
- 以清晰的、按时间顺序的方式总结,
- 提供参考和背景信息,以供进一步探索,
- 让你可以轻松保存或打印成 PDF 文件,以便日后查阅。
对我来说,这将是一个真正的学习系统/工具的圣杯般的结果,尤其是能够把搜索结果离线保存起来以便以后使用!
到了这个时候,只剩一件事可做,那就是开始动手建造;于是乎,我着手设计各个拼图部分。
第一步:设计应用程序界面我想让学习引擎简单易用,并且外观上模仿谷歌。没必要重新发明已经验证过的机制。不过,我认为谷歌也应该有的功能是:一个该死的浅/深模式!
下一步是确保结果以既直观又信息丰富的形式展示。我选择了一个多帧的布局方式。顶部的几帧用于讨论主题,并有一个切换按钮以简化定义。接下来的几个区块将展示时间线本身,在每个时间线事件中都有一个位置来显示支持链接和内容。所有这些内容都被包含在一个区域内,该区域内有一个按钮可以下载学习地图或路径为PDF文件。
按时间顺序结构和PDF和相关链接以丰富内容
步骤 2:添加脑部我想要我的学习引擎具备两个主要功能。
- 每日话题灵感:为此,我利用了谷歌趋势并进行了一些推断来收集可以探讨的话题。
- OpenAI + DeepSeek:我希望利用OpenAI和DeepSeek,并提供选项让用户可以试用两者(右上角旁边的亮/暗模式切换开关可以切换模型)。这样做主要是为了减轻两个模型中的部分审查,我最终使用了o3-mini和deepseek-chat v3模型进行此练习,因为DeepSeek推理模型还没有提供结构化的输出。
热门话题可以提供灵感;设置使用不同的模型有助于更好地进行实验。
一旦我弄清楚了大脑的工作原理,我就需要构建指令和代理,以便开始起草答案。对于指令,我利用了O1关于如何通过起草答案来学习主题的分析来构建提示语。基本上,所有提示语都是为了生成该主题的时间线视图,以帮助学习者理解时间线的构建而设计的。然后我们将这些提示语经过内容丰富代理处理,该代理专门用于构建链接和提供相关参考内容。这有两个好处;
- 基于实际内容:这不仅仅是AI的猜测,而是链接到实际的、可验证的内容。
- 鼓励进一步阅读:想了解更多细节的话,您可以直接跳到来源。
你不应该只停在那里。使用代理来收集数据有时会导致质量较差的链接和无关内容。建立一个内容质量检查系统来审核内容并过滤掉无关项目非常重要。使用这里的推理模型可以带来更好的效果。下面的脚本展示了如何进行质量控制。
这个应用的流程
async function validateResourceRelevancy(
topic: string,
event: string,
resources: Resource[],
): Promise<Resource[]> {
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const response = await openai.chat.completions.create({
模型为: "o3-mini",
messages: [
{
role: "system",
content:
"你是一个内容质量检查员。评估教育资源与主题的相关性。",
},
{
role: "user",
content: `检查这些资源与主题「${topic}」和事件「${event}」的相关性。仅返回相关的资源,格式为 JSON:
${JSON.stringify(resources, null, 2)}`,
},
],
response_format: { type: "json_object" },
});
const validatedResources =
JSON.parse(response.choices[0].message.content).relevant_resources ||
resources;
return validatedResources.slice(0, 5); // 取前五个资源
}
_关于为Deepseek构建的重要说明,请注意。
目前,Deepseek使用的API语法和库与OpenAI相同,这使得为Deepseek构建变得非常简单,只需更新模型名称和基础URL即可。下面的代码片段展示了如何设置一个双切换模型,由于两者使用相同的库,您只需进行少量的代码更改。
const deepSeekConfig = {
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: "https://api.deepseek.com",// Deepseek 基础网址
};
const openAIConfig = {
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://api.openai.com/v1", // OpenAI 基础网址
};
const getOpenAIConfig = (useDeepSeek: boolean) => {
return new OpenAI(useDeepSeek ? deepSeekConfig : openAIConfig);
};
export const progressEmitter = new EventEmitter();
async function generateTopicTimeline(
topic: string,
useDeepSeek: boolean,
): Promise<any[]> {
try {
progressEmitter.emit("progress", {
phase: "正在构建学习旅程的时间线...",
});
const openai = getOpenAIConfig(useDeepSeek);
const response = await openai.chat.completions.create({
model: useDeepSeek ? "deepseek-chat" : "o3-mini",
messages: [
{
role: "system",
content: `您是一位教育领域的专家。请将所有主题呈现为从起源到现代发展的线性历程,并提及未来的影响。无论涉及历史事件、科学概念还是抽象思想,确保时间线延伸到当前时期,展示主题是如何持续发展的。`,
},
{
role: "user",
content: `为“${topic}”创建一个详细的从起源到现代发展以及未来影响的时间线。对于历史主题,使用实际日期。对于概念/想法,使用相对顺序(例如,“基础”,“发展”,“现代的应用”,“未来趋势”)。包含5-8个关键点,确保最后1-2个点涵盖最近的发展和当前/未来的影响。格式:
{
"timeline": [{
"date": 字符串(历史事件的年份/日期,或概念的顺序标识符),
"event": 字符串(事件/概念的标题),
"description": 字符串(解释这个事件/概念的2-3句话),
"significance": 字符串(说明其在发展过程中的重要性)
}]
}
每个点都应建立在先前知识的基础上,从基础到高级理解,形成一个清晰的发展进程。`,
},
],
response_format: { type: "json_object" },
});
let timeline =
JSON.parse(response.choices[0].message.content).timeline || [];
// 为时间线添加最新的相关内容
timeline = await enrichTimelineEvents(topic, timeline);
return timeline;
} catch (error) {
console.error("生成时间线出错:", error);
return [];
}
}
现在是创建代理来帮你做不同的事情。我想能在网路上搜东西、查维基百科,甚至在YouTube上找找视频。
这是一份更简单的代理工作负载版本。我正在研究的一个更复杂版本结合了网页浏览器代理和全面的协调代理。敬请期待我未来的作品。其中一个代理实际上充当个人医疗助手,帮助你管理各种健康相关细节,并随时准备回答你的问题。
export async function enrichTimelineEvents(
topic: string,
timeline: TimelineEvent[],
): Promise<(TimelineEvent & { resources: Resource[] })[]> {
const enrichedTimeline = await Promise.all(
timeline.map(async (event, index) => {
const difficulty =
index < timeline.length / 3
? "初级"
: index < (2 * timeline.length) / 3
? "中等"
: "高级";
const searchQuery = `${topic} ${event.event}`;
const [wiki, articles, videos, books] = await Promise.all([
searchWikipedia({ query: searchQuery }),
searchGoogleResults({ query: searchQuery, difficulty }),
searchYouTubeContent({ query: searchQuery, difficulty }),
searchGoogleBooks({ query: searchQuery, difficulty }),
]);
const extraVideos = videos.slice(0, MAX_VIDEO_RESOURCES);
const limitedBooks = books.slice(0, MAX_BOOK_RESOURCES);
// 至少保留2个视频
const validatedResources = await validateResourceRelevancy(
topic,
event.event,
[...wiki, ...articles, ...limitedBooks]
);
// 单独添加视频以确保它们被包含
const finalResources = [
...validatedResources.slice(0, 3), // 保留前三项验证资源
...extraVideos.slice(0, 2), // 总是包含至少两个视频
...validatedResources.slice(3) // 加上剩余资源
];
return {
...event,
resources: finalResources,
};
}),
);
return enrichedTimeline;
}步骤 3:构建一个连贯的应用程序
我选择使用replit来构建和托管这个应用,因为我有一些没用的积分。这也让我有机会试用replit提供的类似Copilot的编码助手。这是我对此体验所做的非常简短的评价。
Replit 的助手有时会让人感到沮丧和头疼,尤其是对于初学编程的新手来说。特别是在你选择进行调试等功能时,费用可能很高。我的建议是使用 Replit 来设置你的开发环境,并且尽量少用它填充代码细节。把它当作一个真正的代码助手,来处理那些繁琐的工作,比如添加注释、编写重复的代码段等。
这里是项目完整代码,欢迎 fork 并进行修改。
GitHub - theailifestyle/deepsearch通过在GitHub上注册一个账户来为theailifestyle/deepsearch项目做出贡献。 测试与命名拼凑所有东西后,我用各种查询对其进行了测试——包括历史事件、冷门科学主题,甚至是随意的流行文化参考。感觉按时间顺序的方法在实际学习中感觉自然得多。
名称:我选择了deepsearch.guru,因为它就像一位智者一样,能引导你更深入了解你提出的问题。
我们来看看这个实际表现。点击这里: https://deepsearch.guru/
DeepSearch.Guru演示版
这是我从这个项目中得到的几个关键收获。- 当前的搜索引擎界面在帮助快速记忆某个主题时显得过于复杂。
- 目前的搜索引擎更注重速度而非叙述性,对于学习事物而言,采用不同的方法会更有益。
- 开放AI O3 的新推理模型在处理大量文本的用例中表现出色。
- 搜索是一项非常复杂的技术,排名和相关性涉及诸多复杂性和参数。
- 使用DeepSeek构建相对容易,但从开发者的角度来看,DeepSeek的推理体验较为有限。
- Claude Sonnet 3.5 仍然是编码助手中的王者。
观看我这个过程的完整视频以及其他项目。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章